使用 Swift Concurrency(async/await)
现代异步编程的革新
Swift Concurrency 是苹果在 Swift 5.5 引入的革命性异步编程模型,通过 async/await 语法彻底改变了 SwiftUI 中处理异步操作的方式。本章将深入探讨如何将这套现代并发系统与 MVVM 架构优雅结合。
核心概念解析
1. async/await 基础语法
// 传统回调方式
func fetchData(completion: @escaping (Result<Data, Error>) -> Void)
// async/await 版本
func fetchData() async throws -> Data
2. Task 的生命周期管理
- 结构化并发(Structured Concurrency)原则
Task与TaskGroup的使用场景- 取消任务的处理机制
在 ViewModel 中的实现模式
典型 ViewModel 改造案例
class ArticleViewModel: ObservableObject {
@Published var articles: [Article] = []
@Published var isLoading = false
@Published var error: Error?
private let service: ArticleService
func loadArticles() async {
Task { @MainActor in
isLoading = true
do {
articles = try await service.fetchArticles()
error = nil
} catch {
self.error = error
}
isLoading = false
}
}
}
关键实现要点
- 线程安全:使用
@MainActor保证 UI 更新在主线程 - 错误处理:配合 SwiftUI 的
alert修饰符展示错误 - 状态管理:通过
Published属性驱动视图更新
与 Combine 的协同方案
混合使用策略
func fetchData() -> AnyPublisher<Data, Error> {
Future { promise in
Task {
do {
let data = try await networkRequest()
promise(.success(data))
} catch {
promise(.failure(error))
}
}
}
.eraseToAnyPublisher()
}
适用场景对比
| 特性 | async/await | Combine |
|---|---|---|
| 学习曲线 | 较低 | 较高 |
| 链式操作 | 顺序执行 | 操作符组合 |
| 取消机制 | 结构化取消 | 手动管理 |
| 错误处理 | try/catch | sink/receive |
实战:Todo 应用的并发改造
网络层重构示例
protocol TodoService {
func fetchTodos() async throws -> [Todo]
func saveTodo(_ todo: Todo) async throws -> Void
}
class RemoteTodoService: TodoService {
func fetchTodos() async throws -> [Todo] {
let (data, _) = try await URLSession.shared.data(from: endpoint)
return try JSONDecoder().decode([Todo].self, from: data)
}
}
ViewModel 的并发处理
class TodoListViewModel: ObservableObject {
@Published var todos: [Todo] = []
func refresh() async {
do {
todos = try await service.fetchTodos()
} catch {
// 处理错误
}
}
}
性能优化建议
合理使用 Task 优先级:
Task(priority: .userInitiated) { // 关键用户操作 }避免任务爆炸:
func processImages() async { await withTaskGroup(of: Void.self) { group in for image in images { group.addTask { await process(image) } } } }内存管理:
- 使用
weak self防止循环引用 - 及时取消不需要的任务
- 使用
常见问题解决方案
问题1:如何桥接旧版回调代码?
func legacyFetch() async -> Data {
await withCheckedContinuation { continuation in
oldFetchMethod { result in
continuation.resume(returning: result)
}
}
}
问题2:处理并发访问冲突
actor DataCache {
private var storage: [String: Data] = [:]
func store(_ data: Data, for key: String) {
storage[key] = data
}
}
最佳实践提示:对于复杂的异步操作链,考虑创建专门的
AsyncSequence实现,这能获得比 Combine 更简洁的语法表达。
这个章节内容包含了:
1. 从基础语法到高级用法的渐进式讲解
2. 与 MVVM 架构结合的实用模式
3. 性能优化和错误处理的实际建议
4. 与传统方案的对比分析
5. 可直接复用的代码示例
6. 常见问题的解决方案
是否需要针对某个具体方面进行更深入的展开?或者添加其他实战案例?