How do I wait for an asynchronously dispatched block to finish?
grand-central-dispatch, objective-c, unit-testing
Solution
Trying to use a `dispatch_semaphore`. It should look something like this:
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
[object runSomeLongOperationAndDo:^{
STAssert…
dispatch_semaphore_signal(sema);
}];
if (![NSThread isMainThread]) {
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
} else {
while (dispatch_semaphore_wait(sema, DISPATCH_TIME_NOW)) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0]];
}
}
This should behave correctly even if `runSomeLongOperationAndDo:` decides that the operation isn't actually long enough to merit threading and runs synchronously instead.
Problem
I am testing some code that does asynchronous processing using Grand Central Dispatch. The testing code looks like this: ``` [object runSomeLongOperationAndDo:^{ STAssert… }]; ``` The tests have to wait for the operation to finish. My current solution looks like this: ``` __block BOOL finished = NO; [object runSomeLongOperationAndDo:^{ STAssert… finished = YES; }]; while (!finished); ``` Which looks a bit crude, do you know a better way? I could expose the queue and then block by calling `dispatch_sync`: ``` [object runSomeLongOperationAndDo:^{ STAssert… }]; dispatch_sync(object.queue, ^{}); ``` …but that’s maybe exposing too much on the `object`.