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.