swift-concurrency
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSwift 6.2 Concurrency
Swift 6.2 并发编程
Review, fix, and write concurrent Swift code targeting Swift 6.2+. Apply actor
isolation, Sendable safety, and modern concurrency patterns with minimal
behavior changes.
审阅、修复并编写面向Swift 6.2+版本的并发Swift代码。应用actor隔离、Sendable安全机制和现代并发模式,同时将行为变更降至最低。
Triage Workflow
问题排查流程
When diagnosing a concurrency issue, follow this sequence:
诊断并发问题时,请遵循以下步骤:
Step 1: Capture context
步骤1:收集上下文信息
- Copy the exact compiler diagnostic(s) and the offending symbol(s).
- Identify the project's concurrency settings:
- Swift language version (must be 6.2+).
- Whether approachable concurrency (default MainActor isolation) is enabled.
- Strict concurrency checking level (Complete / Targeted / Minimal).
- Determine the current actor context of the code (, custom
@MainActor,actor) and whether a default isolation mode is active.nonisolated - Confirm whether the code is UI-bound or intended to run off the main actor.
- 复制准确的编译器诊断信息和有问题的符号。
- 确定项目的并发设置:
- Swift语言版本(必须为6.2+)。
- 是否已启用易用并发模式(默认MainActor隔离)。
- 严格并发检查级别(完整/目标/最低)。
- 确定代码当前的actor上下文(、自定义
@MainActor、actor)以及是否启用了默认隔离模式。nonisolated - 确认代码是否与UI绑定或需要在主actor之外运行。
Step 2: Apply the smallest safe fix
步骤2:应用最小化安全修复
Prefer edits that preserve existing behavior while satisfying data-race safety.
| Situation | Recommended fix |
|---|---|
| UI-bound type | Annotate the type or relevant members with |
| Protocol conformance on MainActor type | Use an isolated conformance: |
| Global / static state | Protect with |
| Background work needed | Use a |
| Sendable error | Prefer immutable value types. Add |
| Cross-isolation callback | Use |
优先选择能保留现有行为同时满足无数据竞争安全要求的修改。
| 场景 | 推荐修复方案 |
|---|---|
| 与UI绑定的类型 | 为类型或相关成员添加 |
| 主actor类型的协议一致性 | 使用隔离一致性: |
| 全局/静态状态 | 使用 |
| 需要后台执行的任务 | 在 |
| Sendable错误 | 优先使用不可变值类型。仅在确认正确时添加 |
| 跨隔离回调 | 使用 |
Step 3: Verify
步骤3:验证
- Rebuild and confirm the diagnostic is resolved.
- Check for new warnings introduced by the fix.
- Ensure no unnecessary or
@unchecked Sendablewas added.nonisolated(unsafe)
- 重新构建并确认诊断问题已解决。
- 检查修复是否引入新的警告。
- 确保未添加不必要的或
@unchecked Sendable。nonisolated(unsafe)
Swift 6.2 Language Changes
Swift 6.2语言变更
Swift 6.2 introduces "approachable concurrency" -- a set of language changes
that make concurrent code safer by default while reducing annotation burden.
Swift 6.2引入了“易用并发”——一组语言变更,默认让并发代码更安全,同时减少注解负担。
SE-0466: Default MainActor Isolation
SE-0466:默认MainActor隔离
With the compiler flag (or the Xcode 26
"Approachable Concurrency" build setting), all code in a module runs on
by default unless explicitly opted out.
-default-isolation MainActor@MainActorEffect: Eliminates most data-race safety errors for UI-bound code and
global/static state without writing everywhere.
@MainActorswift
// With default MainActor isolation enabled, these are implicitly @MainActor:
final class StickerLibrary {
static let shared = StickerLibrary() // safe -- on MainActor
var stickers: [Sticker] = []
}
final class StickerModel {
let photoProcessor = PhotoProcessor()
var selection: [PhotosPickerItem] = []
}
// Conformances are also implicitly isolated:
extension StickerModel: Exportable {
func export() {
photoProcessor.exportAsPNG()
}
}When to use: Recommended for apps, scripts, and other executable targets
where most code is UI-bound. Not recommended for library targets that should
remain actor-agnostic.
通过编译器标志(或Xcode 26中的“易用并发”构建设置),模块中的所有代码默认在上运行,除非显式退出该模式。
-default-isolation MainActor@MainActor效果: 无需到处编写,即可消除大部分与UI绑定的代码和全局/静态状态的无数据竞争安全错误。
@MainActorswift
// 启用默认MainActor隔离后,以下代码会隐式标记为@MainActor:
final class StickerLibrary {
static let shared = StickerLibrary() // 安全——运行在MainActor上
var stickers: [Sticker] = []
}
final class StickerModel {
let photoProcessor = PhotoProcessor()
var selection: [PhotosPickerItem] = []
}
// 一致性也会被隐式隔离:
extension StickerModel: Exportable {
func export() {
photoProcessor.exportAsPNG()
}
}适用场景: 推荐用于应用、脚本和其他可执行目标,其中大部分代码与UI绑定。不推荐用于需要保持actor无关性的库目标。
SE-0461: nonisolated(nonsending)
SE-0461:nonisolated(nonsending)
Nonisolated async functions now stay on the caller's actor by default instead
of hopping to the global concurrent executor. This is the
behavior.
nonisolated(nonsending)swift
class PhotoProcessor {
func extractSticker(data: Data, with id: String?) async -> Sticker? {
// In Swift 6.2, this runs on the caller's actor (e.g., MainActor)
// instead of hopping to a background thread.
// ...
}
}
@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
}
// No data race -- photoProcessor stays on MainActor
return await photoProcessor.extractSticker(data: data, with: item.itemIdentifier)
}
}Use to explicitly request background execution when needed.
@concurrent非隔离异步函数现在默认保持在调用者的actor上运行,而不是跳转到全局并发执行器。这就是的行为。
nonisolated(nonsending)swift
class PhotoProcessor {
func extractSticker(data: Data, with id: String?) async -> Sticker? {
// 在Swift 6.2中,此函数运行在调用者的actor上(例如MainActor)
// 而不是跳转到后台线程。
// ...
}
}
@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
}
// 无数据竞争——photoProcessor保持在MainActor上
return await photoProcessor.extractSticker(data: data, with: item.itemIdentifier)
}
}当需要后台执行时,使用显式指定。
@concurrent@concurrent Attribute
@concurrent属性
@concurrentswift
class PhotoProcessor {
var cachedStickers: [String: Sticker] = [:]
func extractSticker(data: Data, with id: String) async -> Sticker {
if let sticker = cachedStickers[id] { return sticker }
let sticker = await Self.extractSubject(from: data)
cachedStickers[id] = sticker
return sticker
}
@concurrent
static func extractSubject(from data: Data) async -> Sticker {
// Expensive image processing -- runs on background thread pool
// ...
}
}To move a function to a background thread:
- Ensure the containing type is (or the function itself is).
nonisolated - Add to the function.
@concurrent - Add if not already asynchronous.
async - Add at call sites.
await
swift
nonisolated struct PhotoProcessor {
@concurrent
func process(data: Data) async -> ProcessedPhoto? { /* ... */ }
}
// Caller:
processedPhotos[item.id] = await PhotoProcessor().process(data: data)@concurrentswift
class PhotoProcessor {
var cachedStickers: [String: Sticker] = [:]
func extractSticker(data: Data, with id: String) async -> Sticker {
if let sticker = cachedStickers[id] { return sticker }
let sticker = await Self.extractSubject(from: data)
cachedStickers[id] = sticker
return sticker
}
@concurrent
static func extractSubject(from data: Data) async -> Sticker {
// 耗时的图像处理——运行在后台线程池
// ...
}
}将函数移至后台线程的步骤:
- 确保包含该函数的类型是(或函数本身是
nonisolated)。nonisolated - 为函数添加注解。
@concurrent - 如果函数不是异步的,添加。
async - 在调用处添加。
await
swift
nonisolated struct PhotoProcessor {
@concurrent
func process(data: Data) async -> ProcessedPhoto? { /* ... */ }
}
// 调用者:
processedPhotos[item.id] = await PhotoProcessor().process(data: data)SE-0472: Task.immediate
SE-0472:Task.immediate
Task.immediateswift
Task.immediate { await handleUserInput() }Use for latency-sensitive work that should begin without delay. There is also
which combines immediate start with detached semantics.
Task.immediateDetachedTask.immediateswift
Task.immediate { await handleUserInput() }适用于对延迟敏感、需要立即开始的任务。还有,结合了立即启动和分离语义。
Task.immediateDetachedSE-0475: Transactional Observation (Observations)
SE-0475:事务性观察(Observations)
Observations { }@ObservableAsyncSequenceswift
for await _ in Observations(tracking: { model.count }) {
print("Count changed to \(model.count)")
}Observations { }AsyncSequence@Observableswift
for await _ in Observations(tracking: { model.count }) {
print("Count changed to \(model.count)")
}SE-0481: weak let
SE-0481:weak let
Immutable weak references () that enable conformance for
types holding weak references.
weak letSendable不可变弱引用(),使持有弱引用的类型能够符合一致性要求。
weak letSendableIsolated Conformances
隔离一致性
A conformance that needs MainActor state is called an isolated conformance.
The compiler ensures it is only used in a matching isolation context.
swift
protocol Exportable {
func export()
}
// Isolated conformance: only usable on MainActor
extension StickerModel: @MainActor Exportable {
func export() {
photoProcessor.exportAsPNG()
}
}
@MainActor
struct ImageExporter {
var items: [any Exportable]
mutating func add(_ item: StickerModel) {
items.append(item) // OK -- ImageExporter is on MainActor
}
}If were , adding a would fail:
"Main actor-isolated conformance of 'StickerModel' to 'Exportable' cannot be
used in nonisolated context."
ImageExporternonisolatedStickerModel需要MainActor状态的一致性被称为隔离一致性。编译器确保它仅在匹配的隔离上下文中使用。
swift
protocol Exportable {
func export()
}
// 隔离一致性:仅能在MainActor上使用
extension StickerModel: @MainActor Exportable {
func export() {
photoProcessor.exportAsPNG()
}
}
@MainActor
struct ImageExporter {
var items: [any Exportable]
mutating func add(_ item: StickerModel) {
items.append(item) // 允许——ImageExporter运行在MainActor上
}
}如果是,添加会失败:"Main actor-isolated conformance of 'StickerModel' to 'Exportable' cannot be used in nonisolated context."
ImageExporternonisolatedStickerModelActor Isolation Rules
Actor隔离规则
- All mutable shared state MUST be protected by an actor or global actor.
- for all UI-touching code. No exceptions.
@MainActor - Use only for methods that access immutable (
nonisolated) properties or are pure computations.let - Use to explicitly move work off the caller's actor.
@concurrent - Never use unless you have proven internal synchronization and exhausted all other options.
nonisolated(unsafe) - Never add manual locks (,
NSLock) inside actors.DispatchSemaphore
- 所有可变共享状态必须由actor或全局actor保护。
- 所有接触UI的代码必须使用,无例外。
@MainActor - 仅在访问不可变()属性或纯计算方法时使用
let。nonisolated - 使用显式将任务从调用者的actor移走。
@concurrent - 除非已证明内部同步并穷尽所有其他选项,否则绝不使用。
nonisolated(unsafe) - 绝不在actor内部使用手动锁(、
NSLock)。DispatchSemaphore
Sendable Rules
Sendable规则
- Value types (structs, enums) are automatically when all stored properties are
Sendable.Sendable - Actors are implicitly .
Sendable - classes are implicitly
@MainActor. Do NOT add redundantSendableconformance.Sendable - Non-actor classes: must be with all stored properties
finalandlet.Sendable - is a last resort. Document why the compiler cannot prove safety.
@unchecked Sendable - Use parameters (SE-0430) for finer-grained isolation control.
sending - Use only for third-party libraries you cannot modify. Plan to remove it.
@preconcurrency import
- 值类型(struct、enum)当所有存储属性都是时,会自动符合
Sendable。Sendable - Actor隐式符合。
Sendable - 类隐式符合
@MainActor,请勿添加冗余的Sendable一致性。Sendable - 非actor类:必须是,且所有存储属性为
final并符合let。Sendable - 是最后的手段,需说明编译器无法证明安全性的原因。
@unchecked Sendable - 使用参数(SE-0430)实现更精细的隔离控制。
sending - 仅对无法修改的第三方库使用,并制定移除计划。
@preconcurrency import
Structured Concurrency Patterns
结构化并发模式
Task: Unstructured, inherits caller context.
swift
Task { await doWork() }Task.detached: No inherited context. Use only when you explicitly need to
break isolation inheritance.
Task.immediate: Starts immediately on current actor. Use for
latency-sensitive work.
swift
Task.immediate { await handleUserInput() }async let: Fixed number of concurrent operations.
swift
async let a = fetchA()
async let b = fetchB()
let result = try await (a, b)TaskGroup: Dynamic number of concurrent operations.
swift
try await withThrowingTaskGroup(of: Item.self) { group in
for id in ids {
group.addTask { try await fetch(id) }
}
for try await item in group { process(item) }
}Task: 非结构化,继承调用者上下文。
swift
Task { await doWork() }Task.detached: 不继承上下文,仅在明确需要打破隔离继承时使用。
Task.immediate: 在当前actor上立即启动,适用于对延迟敏感的任务。
swift
Task.immediate { await handleUserInput() }async let: 固定数量的并发操作。
swift
async let a = fetchA()
async let b = fetchB()
let result = try await (a, b)TaskGroup: 动态数量的并发操作。
swift
try await withThrowingTaskGroup(of: Item.self) { group in
for id in ids {
group.addTask { try await fetch(id) }
}
for try await item in group { process(item) }
}Task Cancellation
任务取消
- Cancellation is cooperative. Check or call
Task.isCancelledin loops.try Task.checkCancellation() - Use modifier in SwiftUI -- it handles cancellation on view disappear.
.task - Use for cleanup.
withTaskCancellationHandler - Cancel stored tasks in or
deinit.onDisappear
- 取消是协作式的。在循环中检查或调用
Task.isCancelled。try Task.checkCancellation() - 在SwiftUI中使用修饰符——它会在视图消失时处理取消。
.task - 使用进行清理。
withTaskCancellationHandler - 在或
deinit中取消已存储的任务。onDisappear
Actor Reentrancy
Actor可重入性
Actors are reentrant. State can change across suspension points.
swift
// WRONG: State may change during await
actor Counter {
var count = 0
func increment() async {
let current = count
await someWork()
count = current + 1 // BUG: count may have changed
}
}
// CORRECT: Mutate synchronously, no reentrancy risk
actor Counter {
var count = 0
func increment() { count += 1 }
}Actor是可重入的。在挂起点之间状态可能会发生变化。
swift
// 错误:await期间状态可能已更改
actor Counter {
var count = 0
func increment() async {
let current = count
await someWork()
count = current + 1 // 错误:count可能已更改
}
}
// 正确:同步修改,无重入风险
actor Counter {
var count = 0
func increment() { count += 1 }
}AsyncSequence and AsyncStream
AsyncSequence和AsyncStream
Use to bridge callback/delegate APIs:
AsyncStreamswift
let stream = AsyncStream<Location> { continuation in
let delegate = LocationDelegate { location in
continuation.yield(location)
}
continuation.onTermination = { _ in delegate.stop() }
delegate.start()
}Use / for
single-value callbacks. Resume exactly once.
withCheckedContinuationwithCheckedThrowingContinuation使用桥接回调/代理API:
AsyncStreamswift
let stream = AsyncStream<Location> { continuation in
let delegate = LocationDelegate { location in
continuation.yield(location)
}
continuation.onTermination = { _ in delegate.stop() }
delegate.start()
}使用 / 处理单值回调,必须且只能恢复一次。
withCheckedContinuationwithCheckedThrowingContinuation@Observable and Concurrency
@Observable与并发
- classes should be
@Observablefor view models.@MainActor - Use to own an
@Stateinstance (replaces@Observable).@StateObject - Use (SE-0475) for async observation of
Observations { }properties as an@Observable.AsyncSequence
- 类作为视图模型时,应该标记为
@Observable。@MainActor - 使用持有
@State实例(替代@Observable)。@StateObject - 使用(SE-0475)通过
Observations { }异步观察AsyncSequence属性。@Observable
Common Mistakes
常见错误
- Blocking the main actor. Heavy computation on freezes UI. Move to a
@MainActorfunction.@concurrent - Unnecessary @MainActor. Network layers, data processing, and model code
do not need . Only UI-touching code does.
@MainActor - Actors for stateless code. No mutable state means no actor needed. Use a plain struct or function.
- Actors for immutable data. Use a struct, not an actor.
Sendable - Task.detached without good reason. Loses priority, task-local values, and cancellation propagation.
- Forgetting task cancellation. Store references and cancel them, or use the
Taskview modifier..task - Retain cycles in Tasks. Use when capturing
[weak self]in long-lived stored tasks.self - Semaphores in async context. in async code will deadlock. Use structured concurrency instead.
DispatchSemaphore.wait() - Split isolation. Mixing and
@MainActorproperties in one type. Isolate the entire type consistently.nonisolated - MainActor.run instead of static isolation. Prefer over
@MainActor func.await MainActor.run { }
- 阻塞主actor。 在上执行繁重计算会冻结UI,应移至
@MainActor函数。@concurrent - 不必要的@MainActor。 网络层、数据处理和模型代码不需要,仅接触UI的代码需要。
@MainActor - 为无状态代码使用Actor。 无可变状态则不需要Actor,使用普通struct或函数即可。
- 为不可变数据使用Actor。 使用符合的struct,而非Actor。
Sendable - 无正当理由使用Task.detached。 会丢失优先级、任务本地值和取消传播。
- 忘记任务取消。 存储Task引用并取消,或使用视图修饰符。
.task - Task中的循环引用。 在长期存储的Task中捕获时使用
self。[weak self] - 异步上下文中的信号量。 在异步代码中使用会导致死锁,应使用结构化并发替代。
DispatchSemaphore.wait() - 拆分隔离。 在一个类型中混合和
@MainActor属性,应保持整个类型的隔离一致性。nonisolated - 使用MainActor.run而非静态隔离。 优先使用,而非
@MainActor func。await MainActor.run { }
Review Checklist
审阅检查清单
- All mutable shared state is actor-isolated
- No data races (no unprotected cross-isolation access)
- Tasks are cancelled when no longer needed
- No blocking calls on
@MainActor - No manual locks inside actors
- conformance is correct (no unjustified
Sendable)@unchecked - Actor reentrancy is handled (no state assumptions across awaits)
- imports are documented with removal plan
@preconcurrency - Heavy work uses , not
@concurrent@MainActor - modifier used in SwiftUI instead of manual Task management
.task
- 所有可变共享状态均已通过actor隔离
- 无数据竞争(无未受保护的跨隔离访问)
- 不再需要的任务已被取消
- @MainActor上无阻塞调用
- Actor内部无手动锁
- Sendable一致性正确(无不合理的@unchecked)
- 已处理Actor可重入性(不假设await期间状态不变)
- @preconcurrency导入已记录移除计划
- 繁重任务使用@concurrent而非@MainActor
- SwiftUI中使用.task修饰符而非手动管理Task
Reference Material
参考资料
- See for detailed Swift 6.2 changes, patterns, and migration examples.
references/swift-6-2-concurrency.md - See for the approachable concurrency mode quick-reference guide.
references/approachable-concurrency.md - See for SwiftUI-specific concurrency guidance.
references/swiftui-concurrency.md
- 查看获取详细的Swift 6.2变更、模式和迁移示例。
references/swift-6-2-concurrency.md - 查看获取易用并发模式快速参考指南。
references/approachable-concurrency.md - 查看获取SwiftUI特定的并发指导。
references/swiftui-concurrency.md