Question

I am trying to start a second NSURLConnection after starting the first one. My first one works perfectly: the appropriate delegates are all called, and everything executes as planned. However, after the first one finishes, I create a second one, and nothing happens (the delegate is never called). What could be happening? I know I can't reuse the same NSURLConnection, but I reinitialise it before using it again, so it should be a completely new connection.

Here's my code for starting (both) connections. It's the same instance variable, but it's reinitialised. Also note that the second one is not started until the first one has finished running completely.

if (connection) {
    [connection cancel];
}

currentResponse = nil;
error = nil;

connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
if (!connection) {
    NSLog(@"Connection could not be initialized.");
    [self connectionFinished];
} else {
    [connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [connection start];
}
Was it helpful?

Solution

You haven't shared how you're running it "on a different thread", but the typical problem is if you are using dispatch queues or operation queues, your connection is running asynchronously, itself, and therefore the dispatched operation is completing and getting released and you're losing your connection.

A couple of possible solutions:

  1. You can perform your network operations synchronously in this background operation of yours (this is the only time you should do synchronous network operations). This is the simplest solution, though you haven't explained what you're doing with your NSURLConnection, so this technique may or may not work for you. But if you're just trying to download something from a URL, you can do:

    NSData *data = [NSData dataWithContentsOfURL:url
                                         options:0
                                           error:&error];
    

    This approach doesn't work if you're doing any a little more complicated that requires the NSURLConnectionDataDelegate methods, such challenge-response authentication or if you are streaming using didReceiveData to reduce your app's memory footprint or for performances reasons, etc. But if you're just trying to download data from a remote server (e.g. retrieving an image, an XML/JSON feed, etc.), this is easiest.

  2. In a similar vein (i.e. you don't need the NSURLConnectionDataDelegate methods), but you're you're creating some rich NSURLRequest for your connection, then you can use either sendAsynchronousRequest or sendSynchronousRequest.

  3. If you need the NSURLConnectionDataDelegate calls, you can use the setDelegateQueue (designating a NSOperationQueue) or scheduleInRunLoop (designating a NSRunLoop), and it will automatically dispatch the connection updates to the appropriate queue/runloop. Just make sure to initWithRequest using the startImmediately option of NO, set the delegate queue or runloop, and then start the connection. With this technique, you preserve the full richness of NSURLConnectionDataDelegate if you absolutely need it.

  4. Alternatively, if you're not using operation queues, you could also keep your background operation alive until the connection is done. This approach gives you synchronous behavior in you background operation (keeping your connection alive), while preserving the NSURLConnectionDataDelegate methods. This technique is demonstrated by Apple's XMLPerformance Sample (see the downloadAndParse method of CocoaXMLParser.m and LibXMLParser.m), where they initiate the NSURLConnection and then use the following construct to keep the background operation alive until the NSURLConnectionDataDelegate methods end up setting the done instance variable:

    do {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode 
                                 beforeDate:[NSDate distantFuture]];
    } while (!done);
    

I confess that I find this final approach vaguely dissatisfying and would lean towards the other alternatives, depending upon what flexibility and functionality you need from your NSURLConnection. For us to provide more meaningful counsel, you just need to provide more information about (a) the sort of work you're doing in your NSURLConnectionDataDelegate methods; and (b) which technology you're using to run your code in the background.

For a few more options, also feel free to see GCD and async NSURLConnection.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top