Effective Objective-C 2.0: Item 43: Know When to Use GCD and When to Use Operation Queues

Item 43: Know When to Use GCD and When to Use Operation Queues

GCD is a fantastic technology, but it is sometimes better to use other tools that come as part of the standard system libraries. Knowing when to use each tool is important; using the wrong tool can lead to code that’s difficult to maintain.

The synchronization mechanisms of GCD (see Item 41) can hardly be rivaled. The same goes for single-time code execution through the use of dispatch_once (see Item 45). However, using GCD is not always the best approach for executing tasks in the background. A separate but related technology, NSOperationQueue, allows you to queue operations (subclasses ofNSOperation) that can optionally run concurrently. The similarity to GCD’s dispatch queues is not a coincidence. Operation queues came before GCD, but there is no doubt that GCD is based on the principles made popular by operation queues. In fact, from iOS 4 and Mac OS X 10.6 onward, operation queues use GCD under the hood.

The first difference to note is that GCD is a pure C API, whereas operation queues are Objective-C objects. In GCD, the task that is queued is a block, which is a fairly lightweight data structure (see Item 37). Operations, on the other hand, are Objective-C objects and are therefore more heavyweight. That said, GCD is not always the approach of choice. Sometimes, this overhead is minimal, and the benefits of using full objects far outweigh the downsides.

Through the use of the NSBlockOperation or NSOperationQueue’s addOperationWithBlock:method, the syntax of operation queues can look very similar to plain GCD. Here are some of the benefits of NSOperation and NSOperationQueue:

Image Cancelling operations

With operation queues, this is simple. When run, the cancel method on NSOperation sets internal flags within the operation to tell it not to run, although it cannot cancel an operation that has already startedOn the other hand, GCD queues have no way of cancelling a block once it is scheduled. The architecture is very much “fire and forget.” Implementing cancelling at the application level, however, would be possible but would require writing a lot of code that has already been written in the form of operations.

Image Operation dependencies

An operation can have dependencies on as many other operations as it wishes. This enables you to create a hierarchy of operations dictating that certain operations can execute only after another operation has completed successfully. For example, you may have operations to download and process files from a server that requires a manifest file to be downloaded first before others can be processed. The operation to download the manifest file first could be a dependency of the subsequent download operations. If the operation queue were set to allow concurrent execution, the subsequent downloads could execute in parallel but only after the dependent operation had completed.

Image Key-Value Observing of operation properties

Operations have many properties that are appropriate for KVO, such as isCancelled to determine whether it has been cancelled and isFinished to determine whether it has finished. Using KVO can be useful if you have code that wants to know when a certain task changes state and gives much finer-grained control than GCD over the tasks that are operating.

Image Operation priorities

An operation has an associated priority that ranks it against other operations in a queue. Higher-priority operations are executed before lower-priority ones. The scheduling algorithm is opaque but most certainly will have been carefully thought out. GCD has no direct way of achieving the same thing. It does have queue priorities, but they set a priority for the entire queue rather than individual blocks. Writing your own scheduler on top of this is notsomething you really want to do. Priorities are therefore a useful feature of operations.

Operations also have an associated thread priority, which determines at what priority the thread will execute when the operation runs. You could do this yourself with GCD, but operations make it as simple as setting a property.

Image Reuse of operations

Unless you use one of the built-in concrete subclasses of NSOperation, such asNSBlockOperation, you must create your own subclass. This class, being a normal Objective-C object, can store whatever information you want. When it runs, it has full use of this information and any methods that have been defined on the class. This makes it much more powerful than a simple block that is queued on a dispatch queue. These operation classes can be reused throughout your code, thereby following the “Don’t Repeat Yourself” (DRY) principle of software development.

As you can see, there are many good reasons to use operation queues over dispatch queues. Operation queues mostly provide instant solutions to many of the things you might want to do when executing tasks. Instead of writing complex schedulers, or cancel semantics or priorities yourself, you get them for free when using operation queues.

One API that makes use of operation queues rather than dispatch queues isNSNotificationCenter, which has a method where you can register to observe a notification through a block instead of calling a selector. The method prototype looks like this:

- (id)addObserverForName:(NSString*)name
                  object:(id)object
                   queue:(NSOperationQueue*)queue
              usingBlock:(void(^)(NSNotification*))block

Instead of taking an operation queue, this method could have taken a dispatch queue on which to queue the notification-handler block. But clearly, the design decision was made to make use of the higher-level Objective-C API. In this case, there is little difference between the two in terms of efficiency. The decision was possibly made because using a dispatch queue would introduce an unnecessary dependency on GCD; remember that blocks are not GCD, so the block itself does not introduce this dependency. Or perhaps the developers wanted to keep it all in Objective-C.

You will often hear that you should always use the highest-level API possible, dropping down only when truly necessary. I subscribe to this mantra but with caution. Just because it can be done with the high-level Objective-C variant does not necessarily mean that it’s better. Benchmarking is always the best way to know for sure what is best.

Things to Remember

Image Dispatch queues are not the only solution to multithreading and task management.

Image Operation queues provide a high-level, Objective-C API that can do most of what plain GCD can do. These queues can also do much more complex things that would require additional code on top of GCD.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值