How to wait past dispatch_async before proceeding?

grand-central-dispatch, objective-c

Solution

You're already aware of dispatch groups. Why not just use `dispatch_group_wait()`, which includes support for a timeout? You can use `dispatch_group_enter()` and `dispatch_group_leave()` rather than `dispatch_group_async()` to make the group not done until the internal block for the third-party call with completion is finished.

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_group_t group = dispatch_group_create();

for (...) {
  dispatch_group_enter(group);
  dispatch_async(queue, ^{
    [thirdPartyCodeCallWithCompletion:^{
       dispatch_group_leave(group);
    }];
  }
}

dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, NSECS_PER_SEC));
dispatch_async(dispatch_get_main_queue(), ^{
  //update UI
});

The use of `dispatch_group_wait()` does make this code synchronous, which is bad if run on the main thread. Depending on what exactly is supposed to happen if it times out, you could use `dispatch_group_notify()` as you were and use `dispatch_after()` to just updates the UI rather than trying to pretend the block completed.

Update: I tweaked my code to make sure that "update UI" happens on the main queue, just in case this code isn't already on the main thread.

By the way, I only used `dispatch_async()` for the block which calls `thirdPartyCodeCallWithCompletion:` because your original used `dispatch_group_async()` and I wasn't sure that the hypothetical method was asynchronous. Most APIs which take a completion block are asynchronous, though. If that one is, then you can just invoke it directly.

Problem

I have a series of dispatch_async that I am performing and I would like to only update the UI when they are all done. Problem is the method within dispatch_async calls something in a separate thread so it returns before the data is fully loaded and dispatch_group_notify is called before everything is loaded. So I introduce a infinite loop to make it wait until a flag is set. Is this the best way? See code below. ``` dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); dispatch_group_t group = dispatch_group_create(); for (...) { dispatch_group_async(group, queue, ^{ __block BOOL dataLoaded = NO; [thirdPartyCodeCallWithCompletion:^{ dataLoaded = YES; }]; // prevent infinite loop dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), queue, ^{ dataLoaded = YES; }); // infinite loop to wait until data is loaded while (1) { if (dataLoaded) break; } } dispatch_group_notify(group, dispatch_get_main_queue(), ^{ //update UI }); } ```

Original source

Related problems