OperationQueue — 什么是 Operation 和任务管理

作者: IT Sectr 发布日期: 2026-03-16 阅读时间: 8 分钟

OperationQueue 是 iOS 和 macOS 中的高级任务队列,构建在 Grand Central Dispatch 之上。根据 Apple Developer Documentation, 2026OperationQueue 管理 Operation 实例——封装了工作单元的对象。与 DispatchQueue 不同,OperationQueue 支持操作之间的依赖关系、优先级、KVO 观察以及取消正在运行的任务。OperationQueue 会自动管理线程池,将操作分配到系统可用资源。

要点

  • OperationQueue — 支持操作间依赖的高级队列
  • Operation — 用于封装带有状态的工作单元的抽象类
  • BlockOperation — 用于单个代码块的 Operation 简化实现
  • 依赖关系 决定执行顺序:操作 B 在 A 之后执行
  • 取消 操作通过 KVO 兼容的 isCancelled 属性支持

什么是 OperationQueue 和 Operation

OperationQueue 是 Foundation 框架中管理 Operation 对象执行的类。与 DispatchQueue 不同,OperationQueue 不需要显式指定 serial 或 concurrent 模式——并发执行的操作数量由 maxConcurrentOperationCount 属性控制。值为 1 时队列变为 sequential,其他值则为 concurrent。

Operation 是一个抽象类,表示一个工作单元。每个操作具有状态:ready、executing、finished 或 cancelled。这些状态与 KVO(键值观察)兼容,允许对变化做出响应——例如在操作完成时更新 UI。Operation 会自动管理 isExecuting 和 isFinished 标志。

根据 Apple(2026)的资料,OperationQueue 底层使用 GCD,但增加了 DispatchQueue 所不具备的功能:依赖关系优先级取消 操作。如果应用程序进入后台,OperationQueue 会暂停执行,返回时则恢复。OperationQueue 还会自动考虑 CPU 核心数量并选择最佳线程数。

Operation 的生命周期

每个操作经历四个阶段:pending(等待)、ready(准备执行)、executing(执行中)和 finished(已完成)。cancelled 状态可在完成前的任何阶段出现。状态之间的转换通过 KVO 跟踪——这是响应式 UI 更新的基础。OperationQueue 会自动从队列中移除已完成的操作,并通知依赖的操作其先决条件已完成,从而触发它们的执行。

Operation 和 BlockOperation:任务实现

Operation 是一个抽象类,需要重写 main()start() 方法。在 main() 方法中放置任务代码,而 isExecuting 和 isFinished 状态自动管理。对于异步操作,需要重写 start() 并手动管理状态标志。

BlockOperation 是 Operation 的具体实现,执行一个或多个代码块。如果通过 addExecutionBlock() 添加多个块,BlockOperation 将变为 concurrent。操作仅在执行完所有添加的块后才完成。BlockOperation 是无需继承的简单任务的便捷替代方案。

特性OperationBlockOperation
类类型抽象具体
继承需要不需要
异步性手动管理 KVO自动
代码块一个在 main() 中一个或多个
应用带状态的复杂任务简单一次性任务
适用于依赖、取消、进度快速块、完成回调
内存较高(KVO 和状态)最小,轻量

创建自定义 Operation

要创建自定义操作,请继承 Operation 并重写 main()。在其中,在昂贵操作之前检查 isCancelled 标志,以确保快速取消。这对于下载大文件或批量数据处理至关重要。选择 Operation 还是 BlockOperation 取决于任务的复杂性:对于简单的一次性操作,BlockOperation 就足够了;对于需要状态的可重用逻辑,则继承 Operation。

操作的依赖关系和优先级

依赖关系是 OperationQueue 相对于 DispatchQueue 的关键优势。addDependency(_:) 方法指定操作 B 仅在操作 A 完成后执行。依赖关系形成一个有向无环图(DAG):如果添加循环依赖,队列会忽略它,操作不会执行。

优先级queuePriority 属性设置,值包括:.veryLow、.low、.normal、.high、.veryHigh。优先级影响 ready 操作之间的执行顺序,但不取消依赖关系。OperationQueue 首先考虑依赖关系,然后考虑可用操作之间的优先级。

依赖关系实践示例

一个典型场景——加载个人资料数据:首先加载用户,然后根据其 id 加载好友和帖子。在 用户加载好友加载 之间设置依赖关系可确保正确顺序,无需嵌套 completion handler。

限制并行度

maxConcurrentOperationCount 属性限制同时执行的操作数量。值为 1 创建 sequential 队列,默认值(NSOperationQueueDefaultMaxConcurrentOperationCount)为系统最佳值,取决于设备当前负载。正确配置此参数可防止过度消耗资源:加载图片时 4-6 个 concurrent 操作就足够了,CPU 密集型任务则使用 CPU 核心数。

OperationQueue vs DispatchQueue:比较

选择 OperationQueue 还是 DispatchQueue 取决于 任务复杂性。DispatchQueue 是用于简单异步调用的轻量级工具。OperationQueue 是用于复杂多任务场景的重量级解决方案。Apple 建议从 DispatchQueue 开始,只有在需要依赖关系或取消时才切换到 OperationQueue。对于大多数 iOS 项目,结合使用这两种工具能实现性能和灵活性的最佳平衡。

  • DispatchQueue — 轻量、快速,没有 Operation 对象的开销
  • OperationQueue — 支持依赖、取消、KVO 和优先级
  • DispatchQueue — 适合简单的 async/asyncAfter 任务和通过 serial 进行同步
  • OperationQueue — 对于具有顺序步骤的逐步算法不可或缺
  • DispatchQueue — 通过 Continuation 与 Swift Concurrency(async/await)集成

根据 Ray Wenderlich(2025),在大型 iOS 项目中,OperationQueue 用于带有进度和取消功能的内容下载,而 DispatchQueue 用于所有其他异步操作。比例大约为 20 比 80,DispatchQueue 占优。

Swift 中 OperationQueue 的代码示例

让我们看三个示例:简单的 BlockOperation、带有 依赖关系 的自定义 Operation 以及用于数据加载的可取消操作。

带有 completion 的 BlockOperation

最简单的情况——在 OperationQueue 上执行一个块并通过 completionBlock 处理结果。每个 Operation 都有内置的 completionBlock 属性,在 main() 完成后调用。

swift
let queue = OperationQueue()
let operation = BlockOperation()
operation.addExecutionBlock {
    let data = NetworkService.fetchData()
    OperationQueue.main.addOperation {
        self.updateUI(data)
    }
}
queue.addOperation(operation)

操作之间的依赖关系

依赖关系 确保 parseOperation 仅在 downloadOperation 完成后启动。这消除了嵌套回调的需要。

swift
let download = BlockOperation { self.downloadJSON() }
let parse = BlockOperation { self.parseJSON() }
parse.addDependency(download)

let queue = OperationQueue()
queue.addOperations([download, parse], waitUntilFinished: false)

可取消的自定义 Operation

重写 main() 并定期检查 isCancelled。这样可以在取消时立即停止操作,无需等待昂贵操作完成。

swift
class ImageLoadOperation: Operation {
    override func main() {
        guard !self.isCancelled else { return }
        let image = self.downloadImage()
        guard !self.isCancelled else { return }
        OperationQueue.main.addOperation { self.display(image) }
    }
}

操作取消和 KVO 观察

取消 操作将 isCancelled 标志设置为 true,但不会停止已启动的 main() 方法。main() 中的代码必须自行检查 isCancelled 并在必要时终止。这是 Apple 的架构决策——允许开发者在取消时正确释放资源。

KVO 观察 isFinished 和 isExecuting 属性允许无需显式回调即可响应操作完成。OperationQueue 会自动从队列中移除已完成的操作,但只要还有强引用,它们就会保留在内存中。KVO 是将 OperationQueue 与 RxSwift 或 Combine 等响应式框架集成的基础。

通过 KVO 处理取消

通过 KVO 订阅 isCancelled 允许在操作取消时更新 UI——例如显示占位符而不是已取消的下载。isCancelled 属性与 KVO 兼容,使其便于用于响应式管道。

OperationQueue 最佳实践

不要创建过多的操作——每个 Operation 都是内存中的独立对象。如果任务简短且不需要依赖关系,请直接使用 DispatchQueue。OperationQueue 适用于需要显式依赖、取消和进度监控的复杂场景。

在昂贵操作之前检查 isCancelled 在 main() 方法内部。在文件下载或图像处理的情况下,在每个重要步骤之后进行检查可确保快速响应取消。在 main() 开头和每个大型操作之后使用 if isCancelled { return }

正确管理 completionBlock。操作的 completionBlock 属性在 main() 完成后调用,即使操作被取消。在 completionBlock 内部检查 isCancelled,以避免用错误数据更新 UI。OperationQueue.main 是一个用于 UI 操作的线程安全队列,类似于 DispatchQueue.main。

避免循环依赖——它们会导致循环中的任何操作都无法执行。OperationQueue 不会自动检测循环:如果 A 依赖于 B,而 B 依赖于 A,两者将永远保持在 ready 状态。请提前规划依赖图。

常见问题

OperationQueue 与 DispatchQueue 有什么区别?

OperationQueue 构建在 GCD 之上,增加了依赖关系、优先级、KVO 和操作取消。DispatchQueue 是一个更轻量的工具,适用于没有这些功能的简单异步任务。

如何使队列成为串行队列?

maxConcurrentOperationCount 属性设置为 1。这会将 OperationQueue 转换为 sequential 队列,同时保留所有优势——依赖关系、优先级和取消。

可以取消正在运行的操作吗?

cancel() 方法设置 isCancelled 标志,但不会停止正在执行的 main() 方法。操作的代码必须自行检查 isCancelled 并终止。取消仅适用于 pending 和 ready 操作。

何时应该使用 Operation 而不是 BlockOperation?

当需要 状态管理、异步性或逻辑重用时应继承 Operation。BlockOperation 适用于无需继承的简单一次性任务。

OperationQueue 会阻塞主线程吗?

不会,除非在主线程上调用 waitUntilFinished 方法且参数为 true。操作默认在后台线程上执行,结果通过 OperationQueue.main 返回。

总结

  • OperationQueue — 具有依赖关系、优先级和操作取消的高级队列
  • Operation — 封装具有 KVO 兼容状态的工作的抽象类
  • BlockOperation — 用于一个或多个代码块的简化实现
  • 依赖关系 通过无环图指定操作之间的执行顺序
  • 取消 需要在操作的 main() 方法中手动检查 isCancelled
  • maxConcurrentOperationCount = 1 将队列转换为 sequential 模式
  • OperationQueue vs DispatchQueue — 仅在需要依赖关系或 KVO 时选择 OperationQueue

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读