Choosing Between NSOperation and Grand Central Dispatch

While NSOperation and NSOperationQueue have been available since iOS 2, Grand Central Dispatch, GCD for short, was introduced in iOS 4 and OS X 10.6 Snow Leopard. Both technologies are designed to encapsulate units of work and dispatch them for execution. Because these APIs serve the same goal, developers are often confused when to use which.

Before I answer the questions when to use which API, I would like to discuss the key difference between NSOperation and Grand Central Dispatch.

What Sets Them Apart

Comparing NSOperation and Grand Central Dispatch is comparing apples and oranges. Why is that? With the introduction of Grand Central Dispatch, Apple refactored NSOperation to work on top of Grand Central Dispatch. The NSOperation API is a higher level abstraction of Grand Central Dispatch. If you are using NSOperation, then you are implicitly using Grand Central Dispatch.

Grand Central Dispatch is a low-level C API that interacts directly with Unix level of the system. NSOperation is an Objective-C API and that brings some overhead with it. Instances of NSOperation need to be allocated before they can be used and deallocated when they are no longer needed. Even though this is a highly optimized process, it is inherently slower than Grand Central Dispatch, which operates at a lower level.

Benefits of NSOperation

Since NSOperation is built on top of Grand Central Dispatch, you may be wondering what NSOperation offers that Grand Central Dispatch doesn't. There are several compelling benefits that make NSOperation an interesting choice for a number of use cases.

Dependencies

The NSOperation API provides support for dependencies. This is a powerful concept that enables developers to execute tasks in a specific order. An operation is ready when every dependency has finished executing.

Observable

The NSOperation and NSOperationQueue classes have a number of properties that can be observed, using KVO (Key Value Observing). This is another important benefit if you want to monitor the state of an operation or operation queue.

Pause, Cancel, Resume

Operations can be paused, resumed, and cancelled. Once you dispatch a task using Grand Central Dispatch, you no longer have control or insight into the execution of that task. The NSOperation API is more flexible in that respect, giving the developer control over the operation's life cycle.

Control

The NSOperationQueue also adds a number of benefits to the mix. For example, you can specify the maximum number of queued operations that can run simultaneously. This makes it easy to control how many operations run at the same time or to create a serial operation queue.

When to Use Which

In general, Apple advises developers to use the highest level of abstraction that is available. If we apply this advice, then the NSOperation API should be your first choice.

But why does Apple advise developers to use the highest level of abstraction? With every release, Apple tweaks and optimizes the frameworks and libraries that power the operating system. This usually involves changes affecting low(er)-level APIs. Even though APIs built on top of these low-level APIs change less frequently, they still benefit from the improvements Apple makes to the APIs they are built on.

Great. But when do you use which technology? Should you avoid Grand Central Dispatch only because it is a low-level API? You can use Grand Central Dispatch whenever and wherever you like. Many developers swear by Grand Central Dispatch, but most developers use a combination NSOperation and Grand Central Dispatch.

When to Use NSOperation

The NSOperation API is great for encapsulating well-defined blocks of functionality. You could, for example, use an NSOperation subclass to encapsulate the login sequence of an application.

Dependency management is the icing on the cake. An operation can have dependencies to other operations and that is a powerful feature Grand Central Dispatch lacks. If you need to perform several tasks in a specific order, then operations are a good solution.

You can go overboard with operations if you are creating dozens of operations in a short timeframe. This can lead to performance problems due to the overhead inherent to the NSOperation API.

When to Use Grand Central Dispatch

Grand Central Dispatch is ideal if you just need to dispatch a block of code to a serial or concurrent queue. If you don't want to go through the hassle of creating an NSOperation subclass for a trivial task, then Grand Central Dispatch is a great alternative. Another benefit of Grand Central Dispatch is that you can keep related code together. Take a look at the following example.

let dataTask = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
    // Process Response
    ...

    dispatch_async(dispatch_get_main_queue(), { () -> Void in
        // Update User Interface
        ...
    })
})

In the completion handler of the data task, we process the response and update the user interface by dispatching a closure (or block) to the main queue. This is necessary because we don't know which thread the completion handler is executed on and it most likely is a background thread.

This example illustrates how related code is grouped together. It also highlights the elegance of the Grand Central Dispatch syntax. Asynchronously dispatching a task to the main queue requires only a few lines of code.

NSBlockOperation

The NSOperation class should never be used as is. It is meant to be subclassed. Foundation also provides a concrete subclass that is ready to be used, NSBlockOperation. This class combines the best of both worlds, you can use closures and still benefit from the NSOperation API.

let operation = NSBlockOperation(block: { () -> Void in
    // Do Something
    ...
})

operationQueue.addOperation(operation)

Some consider the NSBlockOperation redundant because you might as well use Grand Central Dispatch instead. I don't agree with this view. As the above example illustrates, the NSBlockOperation combines the elegance of closures and the benefits of operations. There is nothing wrong with NSBlockOperation in my opinion.

Conclusion

In this article, we explored the pros and cons of Grand Central Dispatch and the NSOperation API. I hope it is clear that you don't need to choose one or the other. A combination of both technologies is the right choice for most projects. Try it out and refactor if necessary.

Stop Writing Swift That Sucks

Download the Swift Patterns I Swear By