NSURLConnection - how to wait for completion
Our iPhone currently uses the NSURLConnection sendSynchronousRequest and it works great, except we need to see more of the connection progress and caching, so we move on to the asynchronous NSURLConnection.
What's the easiest way to wait for the asynchronous code to complete? Wrap it in an NSOperation / NSOperationQueue, do a Selector ... or what?
Thanks.
source to share
To use NSURLConnection asynchronously, you provide a delegate when you initialize it in initWithRequest: delegate :. The delegate must inject the NSURLConnection delegate methods. NSURLConnection processing is performed on a different thread, but the delegate methods are called on the thread that started the asynchronous load operation on the associated NSURLConnection object.
source to share
Aside from the notifications mentioned above, a common approach is for the class that needs to know when the URL has finished loading itself to set as a delegate to the class that handles the URL callbacks. Then, when the download of the URL is complete, the delegate is called and reports that the download is complete.
Indeed, if you have blocked a thread, the connection will never go anywhere as it runs on the same thread (yes, even if you use asynch methods).
source to share
I ran into this because our application was using NSURLConnection sendSynchronousRequest
in quite a few places where it made sense, like having some processing going on in a background thread, occasionally needing extra data to complete the processing. Something like that:
// do some processing
NSData * data = someCachedData;
if (data = nil) {
data = [NSURLConnection sendSynchronousRequest....]
someCachedData = data;
}
// Use data for further processing
If you have something like 3 different places in the same thread that do this, breaking it down into separate functions might not be desirable (or just not feasible if you have a large enough code base).
At some point we needed to have a delegate for our connections (for pinning the SSL certificate) and I went trolling the internet for solutions and it was in the form of "just use async and don't fight the framework!" Well it sendSynchronousRequest
exists for some reason, so how to reproduce it with a basic asynchronous connection:
+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse *__autoreleasing *)response error:(NSError *__autoreleasing *)error
{
static NSOperationQueue * requestsQueue;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
requestsQueue = [[NSOperationQueue alloc] init];
requestsQueue.maxConcurrentOperationCount = NSOperationQueueDefaultMaxConcurrentOperationCount;
});
NSCondition * waitLock = [NSCondition new];
[waitLock lock];
__block NSError * returnedError;
__block NSURLResponse * returnedResponse;
__block NSData * returnedData;
__block BOOL done = NO;
[NSURLConnection sendAsynchronousRequest:request
queue:requestsQueue
completionHandler:^(NSURLResponse * response, NSData * data, NSError * connectionError){
returnedError = connectionError;
returnedResponse = response;
returnedData = data;
[waitLock lock];
done = YES;
[waitLock signal];
[waitLock unlock];
}];
if (!done) {
[waitLock wait];
}
[waitLock unlock];
*response = returnedResponse;
*error = returnedError;
return returnedData;
}
Posted here in case someone comes along like me.
Note that this NSURLConnection sendAsynchrounousRequest
can be overridden with whatever method you use to send an asynchronous request, such as creating an object NSURLConnection
with a delegate or something.
source to share