Swift 任务队列简介
\n\n用 Swift 编写的移动和桌面应用程序通常同时执行多项操作:从网络加载数据、处理图像、界面动画。如果没有正确管理这些任务,应用程序可能会“卡死”或运行缓慢。任务队列是一种机制,允许在后台执行代码,而不会阻塞主线程(UI)。
\n\n在 Swift 中,处理队列主要有三种方法:
\n- \n
- Grand Central Dispatch (GCD) — 用于管理队列的低级 API。 \n
- OperationQueue — 基于 GCD 的更高级抽象。 \n
- async/await (Swift 5.5+) — 现代异步语法。 \n
在本文中,我们将通过实用的示例来解析每种方法,即使是初学者也能理解。
\n\n1. Grand Central Dispatch (GCD) — 队列的基础
\n\nGCD 是 Apple 的一个库,用于管理线程池。您只需创建一个队列并将任务提交到其中。系统自行决定在哪个线程上执行代码。
\n\nGCD 中的队列类型
\n- \n
- Main Queue — 在主线程上执行任务(仅限 UI 更新)。 \n
- Global Queues — 具有不同优先级的后台队列(userInteractive、userInitiated、utility、background)。 \n
- Private Queues — 您自己的队列,可以配置为串行(serial)或并行(concurrent)。 \n
示例:在后台加载数据
\nimport UIKit\n\nclass ViewController: UIViewController {\n \n @IBOutlet weak var imageView: UIImageView!\n \n override func viewDidLoad() {\n super.viewDidLoad()\n \n // 在后台队列中启动任务\n DispatchQueue.global(qos: .userInitiated).async {\n let url = URL(string: "https://example.com/image.jpg")!\n if let data = try? Data(contentsOf: url),\n let image = UIImage(data: data) {\n \n // 返回主线程更新 UI\n DispatchQueue.main.async {\n self.imageView.image = image\n }\n }\n }\n }\n}\n\n串行队列 vs 并行队列
\n串行队列一个接一个地执行任务。并行队列可以同时启动多个任务。
\n\n// 串行队列\nlet serialQueue = DispatchQueue(label: "com.example.serial")\nserialQueue.async { print("Task 1") }\nserialQueue.async { print("Task 2") }\n// 输出:Task 1,然后是 Task 2\n\n// 并行队列\nlet concurrentQueue = DispatchQueue(label: "com.example.concurrent", attributes: .concurrent)\nconcurrentQueue.async { print("Task A") }\nconcurrentQueue.async { print("Task B") }\n// 输出:Task A 或 Task B(顺序不保证)\n\n2. OperationQueue — 依赖管理
\n\nOperationQueue 是 GCD 上一个更方便的封装,它允许:
\n- \n
- 设置任务之间的依赖关系。 \n
- 取消任务的执行。 \n
- 管理最大并发操作数。 \n
创建和执行操作
\nlet operationQueue = OperationQueue()\noperationQueue.maxConcurrentOperationCount = 2 // 最多同时执行 2 个任务\n\nlet operation1 = BlockOperation {\n print("操作 1 正在执行")\n Thread.sleep(forTimeInterval: 1)\n}\n\nlet operation2 = BlockOperation {\n print("操作 2 正在执行")\n Thread.sleep(forTimeInterval: 1)\n}\n\n// 设置依赖关系:operation2 仅在 operation1 完成后开始\noperation2.addDependency(operation1)\n\noperationQueue.addOperations([operation1, operation2], waitUntilFinished: false)\n\n