NSOperation

39 阅读2分钟

🧩 为什么需要NSOperation这个“封装”?

主要为了解决GCD在实际复杂业务场景中的几个痛点:

  1. 复杂的依赖关系:这是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];
    
  2. 可取消性:在用户离开页面或需要中断时,取消操作至关重要。

    • GCD:一个dispatch_async提交的Block,一旦入队就无法从队列中移除。
    • NSOperation:可以调用[operation cancel]将其标记为取消状态。一个设计良好的自定义NSOperation子类应该在main方法中定期检查isCancelled属性,以便及时退出。
  3. 状态管理和观察:NSOperation是一个完整的对象,拥有明确的状态机,你可以观察它的isFinishedisExecuting等属性(通过KVO),这在与UI或其他组件联动时非常有用。

  4. 更精确的队列控制:通过NSOperationQueue.maxConcurrentOperationCount,你可以轻松实现一个“并发数受限但非串行”的队列,这在处理网络连接、文件读写等需要限制资源的场景下非常方便。GCD虽然也能实现,但不如NSOperation直观。

  • 使用 GCD 的情况

    • 执行简单的、一次性的、无需管理的后台任务。
    • 实现简单的延迟执行(dispatch_after)。
    • 对性能有极致要求,希望开销最小(GCD是轻量的C API)。
    • 使用DispatchGroup来同步一组简单的任务。
    • 实现线程安全的单例(dispatch_once)。
  • 使用 NSOperation 的情况

    • 任务需要被管理(取消、暂停、恢复、优先级)。
    • 任务之间有复杂的依赖关系
    • 需要观察任务执行状态(KVO)。
    • 需要限制特定队列的并发数量
    • 任务本身是一个可复用的、有状态的实体,适合用对象来表征。