Asynchronous methods are the key to keeping your iOS app responsive. Each method running on the main thread has 1/60 of a second to return before it will affect your screen refresh rate. For long-running operations, the typical paradigm is to execute your code on a separate thread (via an abstraction such as dispatch_queue_t or NSOperationQueue), and when it completes, to invoke a completion handler on the main thread. That way the main thread is available to process touch inputs or render UI elements.
However, there are times when you prefer to treat an asynchronous method synchronously. If you are performing unit tests or invoking from a background thread, it is easier to write your code is classic serial fashion. Here is one way to create a synchronous wrapper around an asynchronous method. This example uses a dispatch_semaphore_t (fancy word for “flag”) to suspend the invoking thread, and NSRunLoop to manually advance the run loop until the semaphore signal is received. There are many other ways to accomplish the same thing, so please let me know if you have a better/preferred way. Enjoy!
//Original asynchronous method - (void)executeInBackgroundWithCompletion:(void(^)(void))completion { NSOperationQueue* callbackQueue = [NSOperationQueue currentQueue]; [[[NSOperationQueue alloc] init] addOperationWithBlock:^{ //do something that takes a long time [callbackQueue addOperationWithBlock:^{ if (completion) { completion(); } }]; }]; } //Synchronous version - (void)executeInBackgroundAndWait { dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); [self executeInBackgroundWithCompletion:^{ dispatch_semaphore_signal(semaphore); }]; while (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW)) { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0]]; }; }
There’s a better way of accomplishing this in Xcode 6. Please see XCTestExpectation https://developer.apple.com/Library/ios/documentation/DeveloperTools/Conceptual/testing_with_xcode/testing_3_writing_test_classes/testing_3_writing_test_classes.html
Thanks! I am indeed using that as well. But it’s only available to subclasses of XCTestCase.