Swift 6 并发:实用迁移指南
Swift 6 改变了什么
Swift 5.x 对并发违规发出警告。Swift 6 将其变成了错误。这意味着可能包含数据竞争的代码在 Swift 6 下无法编译——即使该代码在实践中从未产生竞争。编译器保守地将模糊情况视为错误。
最常见的迁移问题
主线程 UI 更新:在后台任务中从非隔离上下文更新 UI 属性:
// Swift 5 - 警告
func loadData() async {
let result = await fetchData()
self.items = result // 可能不在主线程
}
// Swift 6 - 修复
func loadData() async {
let result = await fetchData()
await MainActor.run {
self.items = result
}
}跨 actor 的 Sendable 违规:将非 Sendable 类型传递给异步上下文:
// 将类标记为 Sendable 或使其 actor 隔离
final class DataModel: @unchecked Sendable {
// 手动保证线程安全
}迁移策略
不要试图一次性修复所有警告。使用分阶段方法:首先让项目在 Swift 6 下编译,使用 @preconcurrency 来抑制尚未准备好修复的警告,然后逐模块解决实际的并发违规。
@preconcurrency import 对于还没有更新到 Swift 6 的第三方库特别有用。
Actor 隔离实践
用 @MainActor 标注视图模型,以确保所有属性更新都在主线程上:
@MainActor
class ViewModel: ObservableObject {
@Published var items: [Item] = []
func load() async {
items = await fetchItems() // 自动在主线程
}
}