How to Create a Synchronous Wrapper Around an Asynchronous Method

Wrapper 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]];
  };
}

About Martin Rybak

I am a New York area software developer and MBA with 10+ years of server-side experience on the Microsoft stack. I've also been a native iOS developer since before the days of ARC. I architect and develop full-stack web applications, iOS apps, database systems, and backend services.

2 responses to “How to Create a Synchronous Wrapper Around an Asynchronous Method

Leave a comment