Sync-Async Pair Pattern – Easy concurrency on iOS

Apple provides many tools for implementing concurrency in your application. NSOperationQueue, GCD, or simply using performSelectorInBackground:withObject: that is available on each and every object, are just some examples. The tools are there, yet implementing good concurrency is hard.

The solution I have found is not yet another tool, or framework, but a simple pattern. I have not found an existing name for the pattern so I call it Sync-Async Pair. The idea is to hide the complexity of asynchronous calls and call-back behind a facade, and have a straightforward synchronous implementation. An implementation that is easy to write, test and extend.

Sync-Async Pair Pattern

As the name suggests the pattern consist of a method pair, one is synchronous, and the other is asynchronous. The asynchronous method is backed by the synchronous implementation, and is only responsible for erecting a simplified facade in front of the sometimes complex concurrent implementation.

The first priority is to expose a clean API, the second priority is an implementation that is simple, testable and maintainable. Turns out that beginning with a clean API design (how to use the code), steers you towards a clean implementation (how to write the code). Most developers do the mistake to first write the code, and then struggle to try to use their own code.

Sync-Asyn Pair begins by defining a public API that then steers towards a clean implementation. Let’s assume we are implementing some kind of a book reader. We need two model objects; CWBook and CWChapter. Both books and chapters are fetched from the network, so we need concurrency in order to not block the UI thread.

For this example let’s focus only on fetching the chapters associated with a book. All other operations would be implemented in a similar fashion. First we need a public API, two methods for the sync-async pair on CWBook, and a delegate protocol.

The synchronous method fetchChaptersWithError: is very straightforward to implement.

How to construct the NSURL, or possibly NSURLRequest is not important. Nor is it important how you actually parse the resulting data sent from the server, that is totally left to our problem domain. Just make it synchronous and super easy to write automatic unit checks for!

Adding Concurrency

Now to the hard part, that is actually quite manageable; adding the concurrency. For this example I will use performSelectorInBackground:withObject:. Your specific implementation might need NSOperationQueue, or GCD if you have special needs such as queues or cancelable operations. The idea will remain the same.

The most basic, and common, implementation for the public async method simply fires off the concurrent operation:

In most cases all it does is request a private method to be performed on a background thread at some point in time. This is also the perfect place to abort operations early, for example a no-op if a request such as fetching a thumbnail is already in progress.

The private method previously launched is where most of the work is done. This is where a NSAutoreleasePool is setup, the synchronous method is called, and the delegate is properly called on the proper thread. The basic implementation for fetching books would be:

For this example I am using my NSInvocation additions to perform the delegate callbacks to the main thread, but it could just as easily been done using GCD. The additions are described in detail and available for download in this blog post, or from in the CWFoundation repo on github.

As you can see the boiler plate code for managing concurrency is actually very minimal, much less than 10 statements in total. The boilerplate code is almost reduced to only calling other methods, leaving very very few opportunities for bugs to sneak in.

Core Data in the Mix

The Sync-Async Pair pattern also lend itself beautifully for writing multi-threaded Core Data. The hassle of juggling NSManagedObjectID and NSManagedObject instances from different contexts can be completely left up to the private implementation that calls the synchronous method.

The private method responsible for calling the synchronous method and handling callbacks could be implemented as such:

Not much extra code, and the ugliness of handling Core Data’s managed contexts is neatly hidden for clients at a single point in the code, that is much easier to test, debug, and maintain than most conventional Core Data code.

Conclusions

The simple Sync-Async Pair pattern makes it easy to write robust concurrent code. It is even a pattern that by design yields an elegant public API. It is also very easy to test, extend and even change the internal implementation completely without affecting any clients.

3 Comments

  1. I don’t know of any other name for this pattern either, though I’ve created similar implementations many times.

    These days however, I almost always prefer to use blocks to do this sort of thing. I call a method and pass in two blocks, one for success and one for failure, and have the method that does the work in the background execute the appropriate block in the foreground. The calling code gets really nice, with both code-paths defined in inline blocks and no need for delegate methods etc.

    • I commonly use blocks for the implementation, but prefer delegates for asynchronous call-backs with more than one option. Such as success/fail.
      I have no concrete reason except that it feels cleaner, it is easy to make a mess with blocks in blocks in blocks. Delegates helps me be disciplined.

      And I also have helpers for transferring NSManagedObject instances across thread boundaries that use NSInvication not blocks. Might do a post on that as well :).

Trackbacks for this post

  1. Best way to implement a workflow based on a series of asynchronous ASIHTTPRequests in iOS?

Leave a Reply