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
});
}
Best Answer
You're already aware of dispatch groups. Why not just use
dispatch_group_wait()
, which includes support for a timeout? You can usedispatch_group_enter()
anddispatch_group_leave()
rather thandispatch_group_async()
to make the group not done until the internal block for the third-party call with completion is finished.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 usedispatch_group_notify()
as you were and usedispatch_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 callsthirdPartyCodeCallWithCompletion:
because your original useddispatch_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.