Swift 的任务队列(iOS/macOS):GCD、OperationQueue 和 Swift Concurrency
iOS 和 macOS 开发需要高效管理并行任务。任务队列(Task Queues)是创建响应迅速且高性能应用程序的基础机制。在 Swift 中,主要有三种方法:经典的 Grand Central Dispatch(GCD)、面向对象的 OperationQueue 以及现代的 async/await(Swift Concurrency)。在本文中,我们将通过实际示例详细解析每一种方法。
1. Grand Central Dispatch(GCD)—— DispatchQueue
GCD 是一个用 C 语言编写的底层库,内置于系统内核中。在 Swift 中,它由 DispatchQueue 类表示。它允许顺序或并发地执行代码块。
队列的主要类型:
- 主队列(Main Queue) — 在主线程上运行的串行队列。用于更新 UI。
- 全局队列(Global Queues) — 具有不同优先级(QoS:userInteractive、userInitiated、utility、background)的并发队列。
- 自定义队列(Custom Queues) — 用户创建的队列(串行或并发)。
示例:异步加载数据并更新 UI
import UIKit
class ViewController: UIViewController { @IBOutlet weak var imageView: UIImageView!
func loadImage(from url: URL) { // 切换到后台队列 DispatchQueue.global(qos: .userInitiated).async { [weak self] in guard let data = try? Data(contentsOf: url), let image = UIImage(data: data) else { return }
// 返回主线程更新 UI DispatchQueue.main.async { self?.imageView.image = image } } }}使用信号量和组
let group = DispatchGroup()let queue = DispatchQueue.global()
group.enter()queue.async { print("任务 1 完成") group.leave()}
group.enter()queue.async { print("任务 2 完成") group.leave()}
group.notify(queue: .main) { print("所有任务已完成")}2. OperationQueue 和 Operation
OperationQueue 是 GCD 之上的一个封装,提供了面向对象的接口。每个任务都是 Operation 类(或其子类 BlockOperation)的一个实例。主要优点包括:依赖关系管理、任务取消以及设置最大并发操作数。
示例:带依赖关系的加载
let queue = OperationQueue()queue.maxConcurrentOperationCount = 2
let fetchData = BlockOperation { print("正在加载数据...")}
let processData = BlockOperation { print("正在处理数据...")}
let updateUI = BlockOperation { print("正在更新界面")}
// 设置依赖关系:processData 将在 fetchData 之后执行processData.addDependency(fetchData)updateUI.addDependency(processData)
queue.addOperations([fetchData, processData, updateUI], waitUntilFinished: false)优先级和任务取消
let operation = BlockOperation { if Task.isCancelled { return } print("正在执行...")}operation.queuePriority = .veryHigh
// 取消操作operation.cancel()3. Swift Concurrency(async/await)
从 Swift 5.5 开始,Apple 引入了内置的异步模型。async/await 允许以线性方式编写异步代码,无需闭包。主要组件包括:Task、TaskGroup、actor。
示例:异步加载图片
import UIKit
class ImageLoader { func loadImage(from url: URL) async throws -> UIImage { let