NSOperation
问题
NSOperation 和 GCD 有什么区别?NSOperation 的优势在哪里?
答案
NSOperation vs GCD
| NSOperation | GCD | |
|---|---|---|
| 层级 | ObjC 对象(更高层) | C 函数(更底层) |
| 取消 | ✅ .cancel() | ❌ 不支持(需 WorkItem) |
| 依赖 | ✅ addDependency | ❌ 只能用 group/barrier |
| 优先级 | ✅ queuePriority | QoS |
| 最大并发数 | ✅ maxConcurrentOperationCount | ❌ 需用 semaphore |
| KVO 监听 | ✅ isReady/isExecuting/isFinished | ❌ |
| 适用场景 | 复杂任务管理 | 简单异步调度 |
基本使用
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 3 // 最大并发数
// BlockOperation
let op1 = BlockOperation {
print("Task 1")
}
let op2 = BlockOperation {
print("Task 2")
}
// 添加依赖:op2 必须在 op1 完成后执行
op2.addDependency(op1)
queue.addOperations([op1, op2], waitUntilFinished: false)
自定义 Operation
class DownloadOperation: Operation {
let url: URL
init(url: URL) { self.url = url }
override func main() {
guard !isCancelled else { return } // 检查取消
let data = try? Data(contentsOf: url)
guard !isCancelled else { return } // 长操作后再次检查
// 处理数据...
}
}
异步 Operation(高级)
默认 Operation 在 main() 返回时标记完成。对于异步操作需要手动管理状态:
class AsyncOperation: Operation {
private var _isExecuting = false
private var _isFinished = false
override var isExecuting: Bool { _isExecuting }
override var isFinished: Bool { _isFinished }
override var isAsynchronous: Bool { true }
override func start() {
guard !isCancelled else {
finish()
return
}
willChangeValue(forKey: "isExecuting")
_isExecuting = true
didChangeValue(forKey: "isExecuting")
// 发起异步请求
performAsyncWork { [weak self] in
self?.finish()
}
}
func finish() {
willChangeValue(forKey: "isExecuting")
willChangeValue(forKey: "isFinished")
_isExecuting = false
_isFinished = true
didChangeValue(forKey: "isExecuting")
didChangeValue(forKey: "isFinished")
}
}
常见面试问题
Q1: 什么时候用 NSOperation 而不是 GCD?
答案:
- 需要取消正在执行的任务
- 需要依赖关系(任务 A 完成后才能执行 B)
- 需要限制并发数量(图片下载)
- 需要 KVO 监听任务状态
Q2: Operation 的 cancel 是真的取消吗?
答案:cancel() 只是将 isCancelled 标记设为 true,并不会强制中断正在执行的任务。开发者需要在 main() 中主动检查 isCancelled 并提前退出。