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.

+1


source to share


4 answers


I answer this in case anyone else runs into the problem in the future. The Apple URLCache sample code is a great example of how this is done. You can find it at:



As John points out in the comment above - don't block / wait - don't notify.

+4


source


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.



+2


source


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).

+2


source


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.

+2


source







All Articles