I have a connection to server , and i want to release its queue, i don't now how.
[NSURLConnection
sendAsynchronousRequest:request
queue:[[NSOperationQueue alloc] init]
completionHandler:^(NSURLResponse *response,
NSData *data,
NSError *error)
//some if else statements
}];
i dont get how to release this queue argument between 2 connections ?
If you are using ARC, you do not have to do anything.
If not, you can include autorelease.
Related
I recently upgraded to MacOS Ventura and discovered that software I'd written in the past to scrape data from a webpage would no longer work. That code used initWithContentsOfURL to access and download a sequence of pages which my code would then process (yes, I know synchronous networking is bad practice, but this is a research app only I use, not commercial software).
I then modified to code to use NSURLSessionTask and dataTaskWithURL to grab the pages asynchronously, which worked great, except... since my software is now making 10 requests in rapid order, the website is generating Error 1015 informing me that I'm being rate limited and temporarily banned.
I guess this means I now have to slow down my code when making the requests? My code looks like this (cutting it down from 10 requests to 3, removing error handling, and NSURL initialization):
NSURLSession *session = [NSURLSession sharedSession];
__block NSURLSessionTask *task1 = nil;
__block NSURLSessionTask *task2 = nil;
__block NSURLSessionTask *task3 = nil;
task1 = [session dataTaskWithURL:pageURL1 completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (data) {
task1Source = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
[task2 resume];
}];
task2 = [session dataTaskWithURL:pageURL2 completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (data) {
task2Source = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
[task3 resume];
}];
task3 = [session dataTaskWithURL:pageURL3 completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (data) {
task3Source = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
}];
[task1 resume];
The site I'm hitting obviously does not like this, which has generated the rate limit error. Is there a preferred way to distribute the requests or otherwise generate an acceptable delay that will be acceptable to the site (I also have a request out to the site's tech support)?
Thanks!
I am new to Mac application development and our existing Mac application contains the following line of code
[NSURLConnection sendSynchronousRequest:request returningResonse:response error:Error
A warning message getting displayed as
sendSynchronousRequest is deprecated in macOS 10.11
and suggesting to use [NSURLSession dataTaskWithRequest:completionHandler:]
I have implemented the following code changes to use NSURLSession as suggested but it is returning the value of data as "nil". Can you please suggest what needs to be done in order to get the required data in response?
__block NSError *WSerror;
__block NSURLResponse *WSresponse;
__block NSData *myData;
NSURLSession *session =[NSURLSession sharedSession];
[[session completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
myData = data;
WSresponse =response;
WSerror = error;
}] resume];
NSString *theXml = [[NSString alloc] initWithData:myData encoding:NSUTF8StringEncoding];
return theXml;
The completion handler is asynchronous. You have to do your work inside the completion handler.
The __block declarations are pointless.
NSURLSession *session =[NSURLSession sharedSession];
[[session completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(#"%#", error);
} else {
NSString *theXml = [[NSString alloc] initWithData: data encoding:NSUTF8StringEncoding];
// do something with `theXml`
}
}] resume];
Having an app written in Objective-C targeting iOS8/9 there are real vantange in performance or stability updating code using NSURLSession
NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithRequest:request
completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error) {
dispatch_sync(dispatch_get_main_queue(), ^{
//UPDATE UI
});
}] resume];
in place of code like the following that use NSURLConnection:
[NSURLConnection sendAsynchronousRequest:request
queue:[CMRequestManager connectionQueue]
completionHandler:^(NSURLResponse *response,
NSData *data, NSError *connectionError)
{
dispatch_sync(dispatch_get_main_queue(), ^{
//UPDATE UI
});
}];
If you decide to run the code in a WatchKit extension or on tvOS at some point in the future, then yes. Otherwise, if the snippet above is representative of the way you're using the API, then I probably wouldn't bother rewriting it. With that said, this is very much a matter of opinion.
How do I get http headers by using sendAsynchronousRequest? Notice that the target URL of the URLRequest only sets headers. When I use sendSynchronousRequest, I can get the http headers by using the NSURLHTTPResponse object. However, in sendAsynchronousRequest, there is only a NSURLResponse object. I have used the following cast strategy to convert NSURLResponse to NSURLHTTPResponse in sendAsynchronousRequest method. This however does not work, blockinkg the main thread without generating any error or exception.\
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
NSHTTPURLResponse *hResponse = (NSHTTPURLResponse*) response;
if ([hResponse respondsToSelector:#selector(allHeaderFields)]) {
NSDictionary *dictionary = [hResponse allHeaderFields];
_myHeader = [dictionary objectForKey:#"myHeader"];
}
}
If I don't use the above code, there is no blocking. I have also notice that the NSData returned by sendAsynchronousRequest hás zero length. Please help
It looks like I didn't get the concept of blocks completely yet...
In my code I have to get out the JSON data from the asychronous block to be returned to from the 'outer' method. I googled and found that if defining a variable with __block, the v̶i̶s̶i̶b̶i̶l̶i̶t̶y̶ _mutability_ of that variable is extended to the block.
But for some reason returned json object is nil.I wonder why?
- (NSMutableDictionary *)executeRequestUrlString:(NSString *)urlString
{
__block NSMutableDictionary *json = nil;
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPShouldHandleCookies:YES];
[request setHTTPMethod:#"GET"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-type"];
NSString *cookieString = [self.userDefaults objectForKey:SAVED_COOKIE];
[request addValue:cookieString forHTTPHeaderField:#"Cookie"];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue currentQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
NSLog(#"dataAsString %#", [NSString stringWithUTF8String:[data bytes]]);
NSError *error1;
NSMutableDictionary * innerJson = [NSJSONSerialization
JSONObjectWithData:data
options:kNilOptions
error:&error1];
json = innerJson;
}];
return json;
}
First, to answer your question:
But for some reason returned json object is nil. I wonder why?
The variable that you are returning has not been set at the time when you return it. You cannot harvest the results immediately after the sendAsynchronousRequest:queue:completionHandler: method has returned: the call has to finish the roundtrip before calling back your block and setting json variable.
Now a quick note on what to do about it: your method is attempting to convert an asynchronous call into a synchronous one. Try to keep it asynchronous if you can. Rather than expecting a method that returns a NSMutableDictionary*, make a method that takes a block of its own, and pass the dictionary to that block when the sendAsynchronousRequest: method completes:
- (void)executeRequestUrlString:(NSString *)urlString withBlock:(void (^)(NSDictionary *jsonData))block {
// Prepare for the call
...
// Make the call
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue currentQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
NSLog(#"dataAsString %#", [NSString stringWithUTF8String:[data bytes]]);
NSError *error1;
NSMutableDictionary * innerJson = [NSJSONSerialization
JSONObjectWithData:data options:kNilOptions error:&error1
];
block(innerJson); // Call back the block passed into your method
}];
}
When you call sendAsynchronousRequest:queue:completionHandler:, you've requested an asynchronous request. So it queues the request and the block and returns immediately. At some point in the future the request is made, and some point after that the completion block is run. But by that time, return json has long since run.
If you want to be able to return the data synchronously, then you must make a synchronous request. That will hang this thread until it completes, so it must not be the main thread.
Check the string when converting data coming from server using below code:
NSLog(#"dataAsString %#", [NSString stringWithUTF8String:[data bytes]]);
if the string is in a proper JSON format, ONLY then your JSON object will be correct.
Hope this hepls!!