在 iOS 多线程开发中,NSOperation 与 GCD(Grand Central Dispatch)的关系可以类比为:NSOperation 是对 GCD 的高级面向对象封装。
虽然底层都利用了线程池,但它们在设计哲学和使用场景上有显著差异。
1. 核心差异对比
| 特性 | GCD (C 语言级别) | NSOperation (Obj-C/Swift 级别) |
|---|---|---|
| 抽象层次 | 底层 API,基于闭包(Block) | 高层抽象,基于对象(Object) |
| 任务依赖 | 实现较复杂(需使用 Group/Barrier) | 天生支持(通过 addDependency:) |
| 取消/暂停 | 较难(只能取消尚未执行的任务) | 非常简单(支持 cancel, pause, resume) |
| 执行顺序 | FIFO(队列先进先出) | 支持优先级(queuePriority) |
| 状态追踪 | 无法直接得知任务进度 | 支持监听 isFinished, isExecuting 等 |
| 性能开销 | 极小,执行速度最快 | 略高(因为有对象创建和状态管理的开销) |
2. NSOperation 的独特优势
A. 强大的依赖关系 (Dependencies)
你可以轻松指定任务 A 必须在任务 B 完成后执行,即使它们在不同的队列中。这在处理复杂的网络请求序列或大文件下载、解压、存储流时非常有用。
Swift
downloadOp.addDependency(unzipOp) // 只有下载完才会解压
B. 灵活的状态监控
NSOperation 提供了一系列 KVO 属性,让你可以实时监控任务的生命周期。
isReady: 是否准备好执行。isExecuting: 是否正在运行。isFinished: 是否已完成(包括成功或被取消)。isCancelled: 是否已取消。
C. 最大并发数控制
通过 maxConcurrentOperationCount,你可以精确控制同时运行的线程数量。这在保护系统资源(如限制同时进行的图片解码数量)时非常有效。
3. GCD 的独特优势
A. 极致的性能
GCD 是基于 C 语言的,直接与系统内核通信。在处理极其频繁、微小的后台任务时,GCD 的分发延迟更低。
B. 丰富的同步原语
- Dispatch Group:监控一组任务是否全部完成。
- Dispatch Semaphore:控制资源访问频率(信号量)。
- Dispatch Barrier:解决“读者-写者”问题,保证线程安全。
- Once (仅限 OC) :确保代码只执行一次(单例模式常用)。
4. 什么时候用哪个?
推荐使用 NSOperation 的场景:
- 任务间有依赖关系:例如“先登录 -> 再拉取配置 -> 再下载资源”。
- 需要随时取消任务:例如在列表快速滚动时,取消已经滑出屏幕的图片下载任务。
- 需要重用代码:你可以通过继承
Operation类来封装复杂的业务逻辑。
推荐使用 GCD 的场景:
- 简单的后台处理:仅仅是想把一段耗时代码丢到后台执行。
- 线程同步/资源保护:需要加锁或使用信号量来保护全局变量。
- 一次性逻辑:只需要执行一次的任务。
总结:封装的力量
GCD 是“执行单元”,侧重于“分发”;NSOperation 是“任务对象”,侧重于“控制”。
在现代项目中,如果业务逻辑比较重,建议优先考虑 NSOperation,因为它能提供更好的可维护性和结构化代码。如果是轻量级的并发控制,GCD 依然是效率之王。