Even more information: I am writing a test framework that waits until all async tasks has completed before checking the results. That why I override dispatch_async. Any other suggestion is welcome. :)
Depending on your situation, this is likely solvable in better ways. As long as you have access to which queues are being used, it's pretty simple. Consider this API, where you are passing the queue to be used:
[object doSomethingAsyncWithCompletion:block1 queue:myQueue];
[object doSomethingElseAsyncWithCompletion:block2 queue:myQueue];
[object doMoreAsyncWithCompletion:block3 queue:myQueue];
Now, you want to wait until all those finish. Assuming this is a custom concurrent queue (not one of the global queues), just use a barrier:
dispatch_barrier_sync(myQueue, ^{
NSLog(@"This will not run until everything else before it on the queue finishes.");
}
But what if you don't know what queue is being used? Well, as long as you control the completion blocks, that's fine, too. (See Waiting on Groups of Queued Tasks.)
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_block_t doneBlock = ^{
dispatch_group_leave(group);
}
dispatch_group_enter(group);
[object doSomethingAsyncWithCompletion:doneBlock queue:myQueue];
dispatch_group_enter(group);
[object doSomethingElseAsyncWithCompletion:doneBlock queue:myQueue];
dispatch_group_enter(group);
[object doMoreAsyncWithCompletion:doneBlock queue:myQueue];
// Wait for all the doneBlocks to fire
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(group);
Of course you could also do this with a semaphore. That's sometimes easier if you just want to convert a single operation from asynchronous to synchronous.
I'd recommend these kinds of approaches rather than trying to hijack dispatch_async itself.