NSURLConnection is running on a different thread. Invalid delegate methods

I run NSURLConnection in another thread:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ NSURLConnection *connection = [NSURLConnection connectionWithRequest:[request preparedURLRequest] delegate:self]; [connection start]; }); 

But my delegate method is not called:

 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData*)data; 

When starting in the main thread, everything is in order. How can I start a connection in another thread and get the delegate methods called in the same thread?

+5
source share
3 answers

GCD creates, destroys, reuses threads implicitly, and there is a chance that the thread you are calling will start to stop immediately. This can cause the delegate to not receive any callbacks.

If you want to receive a callback in the background thread, you can use the setDelegateQueue or sendAsynchronousRequest:queue:completionHandler: method:

 NSURLConnection* connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; [connection setDelegateQueue:[[NSOperationQueue alloc] init]]; [connection start]; 

The easiest way to run NSURLConnection in a background thread via GCD:

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSURLResponse* response = nil; NSError* error = nil; [NSURLConnection sendSynchronousRequest:request] returningResponse:&response error:&error]; NSLog(@"%@", response); }); 
+5
source

Yes, this is the well-known behavior of NSURLConnection , because it needs a run loop to handle delegate events. The most common solution is to (a) create an instance using initWithRequest:delegate:startImmediately: where startImmediately is FALSE ; (b) manually scheduleInRunLoop:forMode: to schedule it in the main run loop; and then (c) start connection.

But, since you have it here, it makes no sense to direct it to the background, since it is already asynchronous, so you just need to initiate this from the main queue, and none of the above is required. You use the above template in special cases (for example, you used a subclass of NSOperation to manage your requests), but in general it is not needed.

Also, FYI, effective iOS9, NSURLConnection deprecated, so you should use NSURLSession . And NSURLSession does not suffer from this limitation.

+2
source

I had a similar problem. Now I run the NSURLConnection request in the main thread - it runs asynchronously, so it will not slow down your application. In connectionDidFinishLoading, I run the following code to process the results of my calls. I am checking because I have an NSURLConnection call that can cause other network calls. Since they are already running in the background thread, I do not want to start a new one.

 - (void)connectionDidFinishLoading:(NSURLConnection *)connection { if ([NSThread isMainThread]) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){ //Background Thread [self processFinishLoading:connection]; }); } else { [self processFinishLoading:connection]; } } 
+1
source

All Articles