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`.

Original source

Related problems