3

I've got a bunch of server requests which I can run asynchronously, but I need to wait for them all to finish before I continue.

dispatch_group_async and it seems quite reasonable, but I can't get it to work. It either blocks forever or doesn't block at all. My latest attempt looks something like....

dispatch_group_t group;

- (void)cleanRoom {
    NSAssert(![NSThread isMainThread], @"not on main thread.");
    group = dispatch_group_create();

    for (Junk *thing in myRoom) {
    // take it off the current thread
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            // register code against group
            dispatch_group_enter(attachmentGroup);
            NSURLConnectionWrapper *wrapper = [[NSURLConnectionWrapper alloc] init];
            wrapper.delegate = self;
            [wrapper sendRequestFor:thing];
        }];
    }

    // wait till the stuff is the group is done
    dispatch_group_wait(attachmentGroup, DISPATCH_TIME_FOREVER);
    NSLog(@"waiting complete!!!!");

    // process the results now that I have them all
}

- (void)wrapperConnectionDone {
    // do a bit more junk
    dispatch_group_leave(group);
}

This causes it to block forever because NSURLConnectionDelegate and NSURLConnectionDataDelegate methods are never getting called. I'm assume I've somehow block their thread, but using NSLog I can confirm the NSURLConnection is on a different thread than my cleanRoom method.

I read a bit about other threads not having run loops to make the callbacks, so I've tried things like connection setDelegateQueue:[NSOperationQueue mainQueue]] and [[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]] but to no noticable effect.

+ sendAsynchronousRequest:queue:completionHandler: doesn't work for me, I've got some ugly authentication. I've seen some good example with that, but I've failed at adapting.

I'm obviously missing some fundamental bit, but I can't find it.

madth3
  • 7,275
  • 12
  • 50
  • 74
DBD
  • 23,075
  • 12
  • 60
  • 84
  • 1
    I've been using NSOperations to do this, and when the queue goes to 0 you know you are done. A really easy to use easy to employ set of code - a operations manager and a sample NSOperation subclass, can be found here: github.com/dhoerl/NSOperation-WebFetches-MadeEasy. There is a "How-To" in OperationsRunner.h That said there are many of these on github. – David H Aug 22 '12 at 13:37
  • You have an excellent point. Earlier I had a more simplified code with `setDelegateQueue:[NSOperationQueue mainQueue]]` on my `NSURLConnection` instead of creating a extra GCD block in the calling code. Now that I have things working with GCD, I might go back and switch it back for easier readability. In many cases NSOperation and GCD can be used to do the same thing. For others who might follow, http://stackoverflow.com/questions/10373331/nsoperation-vs-grand-central-dispatch was quite descriptive. – DBD Aug 22 '12 at 15:37

1 Answers1

2

NSURLConnection needs to run on a thread with a processed run-loop. The simplest such thread is the main thread. So just dispatch_async these connection creations to dispatch_get_main_queue() and the rest of your dispatch_group logic should be fine. Keep in mind that the delegate methods will be called on the main thread (from the NSURLConnection Overview):

These delegate methods are called on the thread that started the asynchronous load operation for the associated NSURLConnection object.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • Great, it's working. It turned out to be a compound problem. I had unwittingly block my main thread in another process so `NSURLConnectionDelegate` calls weren't being made even when I put them on the main thread with the run loop. You answer solved the one issue and let me look in the right place for the other. – DBD Aug 22 '12 at 15:31