you're reading...


A Swift Promise

Although having been known since 1976, the futures and promises pattern gets a new breath of life as the collective programming body of knowledge moves away from thread-spawning into preference of asynchronous processing (refer to the c10k problem). It appears that node.js stack and community have been in the forefront of this renaissance of promises attributed to the number of subsequent libraries in other languages that emulates how JavaScript does asynchronous-ness.  Probably this is rooted  from the single-threaded nature of JavaScript as a programming language and not many other imperative languages has direct support of parallelism (most, maybe except for Ada, has parallelism mostly done as library calls and not built into the compiler).

Promise to deliver this vehicle

In the sphere of Apple computers programming, there have been a number of libraries (e.g. BrightFutures) or frameworks (e.g. ReactiveCocoa) implementing the future/promise pattern. However you rightly wouldn’t want to include such complex libraries or frameworks into your project when your needs are fairly modest — even if they are open source. Adding more dependencies into your project means increasing the risk of maintenance burden later on. There’s no guarantee that these libraries are going to be maintained to remain compatible with changes in the operating system API or language features (e.g. Swift 3.x to Swift 4.x). There’s not even any guarantee that the maintainers will keep their own API stable, and this impacts your code and could be detrimental to your own productivity during maintenance (this latter part is probably more relevant for those developing products but less so in the world of one-shot consulting gigs). Hence if you expect to maintain the project for a long period of time — over two operating system releases or so — you should practice restraint on adding 3rd party dependencies.

I’ve recently found futures/promises to be useful in state preservation and restoration, notably with respect of coordinating UI state restoration of a tvOS app with loading the associated data from persistent storage. Having a promise in place of the persistent store object greatly simplifies code paths handling different orders that persisted data can be shown on-screen.  This was part of my Wake on LAN app for the Apple TV and a future object is used to wrap references to the primary persistence manager.

Normally without state restoration, data are loaded first and then the user interface is displayed second. However when the user interface was just restored, then the it gets created and shown before the time data are loaded from persistent storage. During restoration time, as soon as the application completes initialization, every view controller that was preserved gets restored — regardless whether the underlying data store was ready or not during restore time. In turn, those user interface elements are expected to configure itself from information that was given out when it was preserved. Likely the persistent store would only be available after restoration has completed. That’s why those view controllers would need to handle two cases of data loading time — the normal case in which data were readily available at viewDidLoad and the restoration case in which data were only available some time later after it had been shown on screen.

User Interface Restoration Comparison

This diagram compares the “typical” case vs the “restoration” case. Typically the persistence layer (e.g. Core Data stack) have been set up and the data items are loaded prior to displaying the view. However the restoration mechanism instantiates, restores, and displays the user interface prior to handing it back to application code. Hence during restoration, views gets initialized with dummy data obtained from the restoration information and then reloads itself from the “official source” when the latter becomes available.

Since my needs of futures for this project were pretty modest, I shied away from bringing in complex libraries for it. Indeed, my bare-bones implementation for future/promises is only about 100 lines. The public interface of the class was loosely inspired by Java’s CompletableFuture class but only with the methods that I needed at the time.

The class uses two dispatch queues internally. One is a privately-owned serial queue for coordinating access to the promised object and the corresponding list of promise completion handlers. Whereas the other dispatch queue is for invoking the completion handlers when the promise gets fulfilled. That last one defaults to the global concurrent queue and can be overridden at construction time to use any other queue. This is to fulfill the Cocoa convention of completion handlers being called “in the main queue or an arbitrary queue”. Since it’s not a user interface class, it doesn’t make sense to default it to the main queue.

The diagram below shows how, the future object collects registration on promise completions when the object hasn’t been fulfilled. Upon completion of the promise, the completion handlers gets called with the resulting object. If the completion registration gets called after fulfillment of the promise, the future object would simply call the given promise completion handler. Registration on promises can come from any queue (thread) since the object would just dispatch the request into the internal serial queue. Similarly the completion handler gets called on the global queue (unless another queue was specified), regardless of whether the promise was fulfilled when the registration was made.

Time Diagram of promise completion

In the above diagram, a, b, and c are clients wanting the promised object. Both a and b requests the object prior to the promise being fulfilled, hence their completion handlers are queued and retained. However client c made the request when the object is already available, and thus its completion handler gets called almost immediately. Registrations to get the promised object can be done from any dispatch queue since the future would simply re-dispatch to an internal serial queue to prevent any race condition. However, the callbacks are done on the callback queue (by default is a global concurrent queue) regardless of whether the request was queued or not, to ensure uniformity of the behavior.

Last but not least, the class was written in Swift 3.1 (Xcode 8 era). BSD-licensed for use in your project. Hopefully there wont be any big changes when Xcode 9 hits.

That’s all for now, take care.

Do you enjoy this post? Enter your e-mail address below to receive articles like this one in your mailbox.
* indicates required


No comments yet.

Leave a Reply

Free Updates!

Learn how to grow your indie business while keeping your day job.



Keep updated!

Don't miss out on new articles!