Future Cocoa Operation

In Java you have for quite some time had the Future interface for encapsulating an asynchronous calculation. Cocoa has had the abstract NSOperation class to encapsulate asynchronous operations.

NSOperation do not have any facilities for returning a result when done as the Future do, you are left to implement this on your own. Which I have done a few times, and as a rule of thumb, make the solution generic when needed for the third time.

Operations works perfectly for background network activities. One common network activity is search-as-you-type, in this case you need to also cancel the previous operation if it has not yet been completed, so lets built this behavior into the generic solution as well.

API Design

What we want is an subclass of NSOperation that provides a future result, lets call this class CWFutureOperation. It is abstract, so users are supposed to subclass and implement main method just as for NSOperation, only difference is that the main method implementation must call setResult: before exiting.

The result that is set in the main method implementation can then be fetched using the blocking method result, equivalent to get() from the Java Future. As an alternative we would also like to be handed the method upon completion via a target-action pair. If the target-action pair is only called for finished operations that are not cancelled, then we get the search-as-you-type behavior for free.

It is also nice to be able to wrap up any method returning an object in a future operation as a convenience, so lets add that as well to our class interface:

Implementation

The client of the code must be able to fetch the result and the CWFutureOperation subclass must be able to set the result. The result method should block until the operation is finished if needed, and must properly return a result that can survive the operation that might be in a release pool. The implementation for this is straight forward, only minor complexity added in order to allow the result to be set multiple times:

The reason that we flag if the result has been set is because we want to throw an exception if the subclass implementation of the main method failes to set the result before exiting, we add this behavior by overriding the start method in CWFutureOperation.

The start method will also call the target-action pair upon completion if the operation has not been cancelled. The target selector is always called on the main thread, this is so that we safely can update any UI using the calculated result without adding even more threading code.

Conclusion

The total amount of code is not muFuturesch, but this generic class adds a pattern to follow making design decisions for new application easy and consistent.

Solving the age old search-as-you-type problem can be as simple as this (Many assumptions, but you get the idea):

The full source code including unit tests, and some additional categories for making operation queue life easier, can be downloaded here.

1 Comment

  1. Very nice! This will be most useful.

Leave a Reply