🧩 为什么需要NSOperation这个“封装”?
主要为了解决GCD在实际复杂业务场景中的几个痛点:
-
复杂的依赖关系:这是NSOperation最闪亮的优点。
- GCD实现:你需要使用
DispatchGroup、信号量或嵌套回调,代码会迅速变得复杂难懂(“回调地狱”)。 - NSOperation实现:只需一句
operationB.addDependency(operationA),逻辑清晰直观。
objectivec
// 用NSOperation优雅地表达依赖:下载 -> 解压 -> 处理 NSOperation *downloadOp = [DownloadOperation new]; NSOperation *unzipOp = [UnzipOperation new]; NSOperation *processOp = [ProcessOperation new]; [unzipOp addDependency:downloadOp]; [processOp addDependency:unzipOp]; NSOperationQueue *queue = [NSOperationQueue new]; [queue addOperations:@[downloadOp, unzipOp, processOp] waitUntilFinished:NO]; - GCD实现:你需要使用
-
可取消性:在用户离开页面或需要中断时,取消操作至关重要。
- GCD:一个
dispatch_async提交的Block,一旦入队就无法从队列中移除。 - NSOperation:可以调用
[operation cancel]将其标记为取消状态。一个设计良好的自定义NSOperation子类应该在main方法中定期检查isCancelled属性,以便及时退出。
- GCD:一个
-
状态管理和观察:NSOperation是一个完整的对象,拥有明确的状态机,你可以观察它的
isFinished、isExecuting等属性(通过KVO),这在与UI或其他组件联动时非常有用。 -
更精确的队列控制:通过
NSOperationQueue.maxConcurrentOperationCount,你可以轻松实现一个“并发数受限但非串行”的队列,这在处理网络连接、文件读写等需要限制资源的场景下非常方便。GCD虽然也能实现,但不如NSOperation直观。
-
使用 GCD 的情况:
- 执行简单的、一次性的、无需管理的后台任务。
- 实现简单的延迟执行(
dispatch_after)。 - 对性能有极致要求,希望开销最小(GCD是轻量的C API)。
- 使用
DispatchGroup来同步一组简单的任务。 - 实现线程安全的单例(
dispatch_once)。
-
使用 NSOperation 的情况:
- 任务需要被管理(取消、暂停、恢复、优先级)。
- 任务之间有复杂的依赖关系。
- 需要观察任务执行状态(KVO)。
- 需要限制特定队列的并发数量。
- 任务本身是一个可复用的、有状态的实体,适合用对象来表征。