
关于
Swift 6.2 易用并发——默认单线程,使用 @concurrent 显式后台卸载,隔离一致性用于主 Actor 类型。
name: swift-concurrency-6-2 description: Swift 6.2 易用并发 — 默认单线程,@concurrent 用于显式后台卸载,隔离一致性用于主 Actor 类型。
Swift 6.2 易用并发
采用 Swift 6.2 并发模型的模式,代码默认单线程运行,并发通过显式引入。消除常见数据竞争错误而不牺牲性能。
激活时机
- 将 Swift 5.x 或 6.0/6.1 项目迁移到 Swift 6.2
- 解决数据竞争安全编译器错误
- 设计基于 MainActor 的应用架构
- 将 CPU 密集型工作卸载到后台线程
- 为 MainActor 隔离类型实现协议一致性
- 在 Xcode 26 中启用易用并发构建设置
核心问题:隐式后台卸载
在 Swift 6.1 及更早版本中,async 函数可能被隐式卸载到后台线程,即使在看似安全的代码中也会导致数据竞争错误:
// Swift 6.1: ERROR
@MainActor
final class StickerModel {
let photoProcessor = PhotoProcessor()
func extractSticker(_ item: PhotosPickerItem) async throws -> Sticker? {
guard let data = try await item.loadTransferable(type: Data.self) else { return nil }
// Error: Sending 'self.photoProcessor' risks causing data races
return await photoProcessor.extractSticker(data: data, with: item.itemIdentifier)
}
}
Swift 6.2 修复了这个问题:async 函数默认留在调用 Actor 上。
// Swift 6.2: OK — async stays on MainActor, no data race
@MainActor
final class StickerModel {
let photoProcessor = PhotoProcessor()
func extractSticker(_ item: PhotosPickerItem) async throws -> Sticker? {
guard let data = try await item.loadTransferable(type: Data.self) else { return nil }
return await photoProcessor.extractSticker(data: data, with: item.itemIdentifier)
}
}
核心模式 — 隔离一致性
MainActor 类型现在可以安全地遵循非隔离协议:
protocol Exportable {
func export()
}
// Swift 6.1: ERROR — crosses into main actor-isolated code
// Swift 6.2: OK with isolated conformance
extension StickerModel: @MainActor Exportable {
func export() {
photoProcessor.exportAsPNG()
}
}
编译器确保一致性仅在主 Actor 上使用:
// OK — ImageExporter is also @MainActor
@MainActor
struct ImageExporter {
var items: [any Exportable]
mutating func add(_ item: StickerModel) {
items.append(item) // Safe: same actor isolation
}
}
// ERROR — nonisolated context can't use MainActor conformance
nonisolated struct ImageExporter {
var items: [any Exportable]
mutating func add(_ item: StickerModel) {
items.append(item) // Error: Main actor-isolated conformance cannot be used here
}
}
核心模式 — 全局和静态变量
使用 MainActor 保护全局/静态状态:
// Swift 6.1: ERROR — non-Sendable type may have shared mutable state
final class StickerLibrary {
static let shared: StickerLibrary = .init() // Error
}
// Fix: Annotate with @MainActor
@MainActor
final class StickerLibrary {
static let shared: StickerLibrary = .init() // OK
}
MainActor 默认推断模式
Swift 6.2 引入了默认推断 MainActor 的模式 — 无需手动注解:
// With MainActor default inference enabled:
final class StickerLibrary {
static let shared: StickerLibrary = .init() // Implicitly @MainActor
}
final class StickerModel {
let photoProcessor: PhotoProcessor
var selection: [PhotosPickerItem] // Implicitly @MainActor
}
extension StickerModel: Exportable { // Implicitly @MainActor conformance
func export() {
photoProcessor.exportAsPNG()
}
}
此模式为可选启用,推荐用于应用、脚本和其他可执行目标。
核心模式 — @concurrent
当需要后台执行时,使用 @concurrent 显式标记:
@MainActor
final class StickerModel {
let photoProcessor = PhotoProcessor()
func extractSticker(_ item: PhotosPickerItem) async throws -> Sticker? {
guard let data = try await item.loadTransferable(type: Data.self) else { return nil }
// Explicitly offload to background
return await photoProcessor.extractStickerInBackground(data: data)
}
}
extension PhotoProcessor {
@concurrent
func extractStickerInBackground(data: Data) async -> Sticker? {
// Runs on background thread — CPU-intensive work here
let processed = heavyImageProcessing(data)
return Sticker(image: processed)
}
}
迁移策略
从 Swift 6.1 迁移
- 启用易用并发:在 Xcode 26 构建设置中启用
- 移除不必要的 nonisolated:async 函数不再需要
nonisolated来避免数据竞争 - 添加 @concurrent:对确实需要后台执行的函数添加
- 使用隔离一致性:替换
@preconcurrency协议一致性 - 启用 MainActor 默认推断:对应用目标逐步启用
关键规则
- 默认:代码在调用者的 Actor 上运行
@concurrent:显式选择后台执行- 隔离一致性:
@MainActor Exportable限制使用上下文 nonisolated:选择退出 Actor 隔离(用于纯计算)
最佳实践
- ✅ 让大多数代码保持默认(单线程、MainActor)
- ✅ 仅对 CPU 密集型工作使用
@concurrent - ✅ 使用隔离一致性而非
@preconcurrency - ✅ 对应用目标启用 MainActor 默认推断
- ❌ 不要对每个 async 函数都添加
@concurrent - ❌ 不要使用
nonisolated来绕过编译器错误
兼容工具
Claude CodeCursor
标签
移动端
