跳到主要内容

NSOperation

问题

NSOperation 和 GCD 有什么区别?NSOperation 的优势在哪里?

答案

NSOperation vs GCD

NSOperationGCD
层级ObjC 对象(更高层)C 函数(更底层)
取消.cancel()❌ 不支持(需 WorkItem)
依赖addDependency❌ 只能用 group/barrier
优先级queuePriorityQoS
最大并发数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 并提前退出。

相关链接