swift-concurrency

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Swift 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 (
    @MainActor
    , custom
    actor
    ,
    nonisolated
    ) and whether a default isolation mode is active.
  • 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.
SituationRecommended fix
UI-bound typeAnnotate the type or relevant members with
@MainActor
.
Protocol conformance on MainActor typeUse an isolated conformance:
extension Foo: @MainActor Proto
.
Global / static stateProtect with
@MainActor
or move into an actor.
Background work neededUse a
@concurrent
async function on a
nonisolated
type.
Sendable errorPrefer immutable value types. Add
Sendable
only when correct.
Cross-isolation callbackUse
sending
parameters (SE-0430) for finer control.
优先选择能保留现有行为同时满足无数据竞争安全要求的修改。
场景推荐修复方案
与UI绑定的类型为类型或相关成员添加
@MainActor
注解。
主actor类型的协议一致性使用隔离一致性:
extension Foo: @MainActor Proto
全局/静态状态使用
@MainActor
保护或移入actor中。
需要后台执行的任务
nonisolated
类型上使用
@concurrent
异步函数。
Sendable错误优先使用不可变值类型。仅在确认正确时添加
Sendable
一致性。
跨隔离回调使用
sending
参数(SE-0430)实现更精细的控制。

Step 3: Verify

步骤3:验证

  • Rebuild and confirm the diagnostic is resolved.
  • Check for new warnings introduced by the fix.
  • Ensure no unnecessary
    @unchecked Sendable
    or
    nonisolated(unsafe)
    was added.
  • 重新构建并确认诊断问题已解决。
  • 检查修复是否引入新的警告。
  • 确保未添加不必要的
    @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
-default-isolation MainActor
compiler flag (or the Xcode 26 "Approachable Concurrency" build setting), all code in a module runs on
@MainActor
by default unless explicitly opted out.
Effect: Eliminates most data-race safety errors for UI-bound code and global/static state without writing
@MainActor
everywhere.
swift
// 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.
通过
-default-isolation MainActor
编译器标志(或Xcode 26中的“易用并发”构建设置),模块中的所有代码默认在
@MainActor
上运行,除非显式退出该模式。
效果: 无需到处编写
@MainActor
,即可消除大部分与UI绑定的代码和全局/静态状态的无数据竞争安全错误。
swift
// 启用默认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
nonisolated(nonsending)
behavior.
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
@concurrent
to explicitly request background execution when needed.
非隔离异步函数现在默认保持在调用者的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属性

@concurrent
ensures a function always runs on the concurrent thread pool, freeing the calling actor to run other tasks.
swift
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:
  1. Ensure the containing type is
    nonisolated
    (or the function itself is).
  2. Add
    @concurrent
    to the function.
  3. Add
    async
    if not already asynchronous.
  4. Add
    await
    at call sites.
swift
nonisolated struct PhotoProcessor {
    @concurrent
    func process(data: Data) async -> ProcessedPhoto? { /* ... */ }
}

// Caller:
processedPhotos[item.id] = await PhotoProcessor().process(data: data)
@concurrent
确保函数始终在并发线程池上运行,释放调用者的actor以执行其他任务。
swift
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 {
        // 耗时的图像处理——运行在后台线程池
        // ...
    }
}
将函数移至后台线程的步骤:
  1. 确保包含该函数的类型是
    nonisolated
    (或函数本身是
    nonisolated
    )。
  2. 为函数添加
    @concurrent
    注解。
  3. 如果函数不是异步的,添加
    async
  4. 在调用处添加
    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.immediate
starts executing synchronously on the current actor before any suspension point, rather than being enqueued.
swift
Task.immediate { await handleUserInput() }
Use for latency-sensitive work that should begin without delay. There is also
Task.immediateDetached
which combines immediate start with detached semantics.
Task.immediate
会在任何挂起点之前同步在当前actor上开始执行,而不是进入队列等待。
swift
Task.immediate { await handleUserInput() }
适用于对延迟敏感、需要立即开始的任务。还有
Task.immediateDetached
,结合了立即启动和分离语义。

SE-0475: Transactional Observation (Observations)

SE-0475:事务性观察(Observations)

Observations { }
provides async observation of
@Observable
types via
AsyncSequence
, enabling transactional change tracking.
swift
for await _ in Observations(tracking: { model.count }) {
    print("Count changed to \(model.count)")
}
Observations { }
通过
AsyncSequence
提供对
@Observable
类型的异步观察,支持事务性变更跟踪。
swift
for await _ in Observations(tracking: { model.count }) {
    print("Count changed to \(model.count)")
}

SE-0481: weak let

SE-0481:weak let

Immutable weak references (
weak let
) that enable
Sendable
conformance for types holding weak references.
不可变弱引用(
weak let
),使持有弱引用的类型能够符合
Sendable
一致性要求。

Isolated 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
ImageExporter
were
nonisolated
, adding a
StickerModel
would fail: "Main actor-isolated conformance of 'StickerModel' to 'Exportable' cannot be used in nonisolated context."
需要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上
    }
}
如果
ImageExporter
nonisolated
,添加
StickerModel
会失败:"Main actor-isolated conformance of 'StickerModel' to 'Exportable' cannot be used in nonisolated context."

Actor Isolation Rules

Actor隔离规则

  1. All mutable shared state MUST be protected by an actor or global actor.
  2. @MainActor
    for all UI-touching code. No exceptions.
  3. Use
    nonisolated
    only for methods that access immutable (
    let
    ) properties or are pure computations.
  4. Use
    @concurrent
    to explicitly move work off the caller's actor.
  5. Never use
    nonisolated(unsafe)
    unless you have proven internal synchronization and exhausted all other options.
  6. Never add manual locks (
    NSLock
    ,
    DispatchSemaphore
    ) inside actors.
  1. 所有可变共享状态必须由actor或全局actor保护。
  2. 所有接触UI的代码必须使用
    @MainActor
    ,无例外。
  3. 仅在访问不可变(
    let
    )属性或纯计算方法时使用
    nonisolated
  4. 使用
    @concurrent
    显式将任务从调用者的actor移走。
  5. 除非已证明内部同步并穷尽所有其他选项,否则绝不使用
    nonisolated(unsafe)
  6. 绝不在actor内部使用手动锁(
    NSLock
    DispatchSemaphore
    )。

Sendable Rules

Sendable规则

  1. Value types (structs, enums) are automatically
    Sendable
    when all stored properties are
    Sendable
    .
  2. Actors are implicitly
    Sendable
    .
  3. @MainActor
    classes are implicitly
    Sendable
    . Do NOT add redundant
    Sendable
    conformance.
  4. Non-actor classes: must be
    final
    with all stored properties
    let
    and
    Sendable
    .
  5. @unchecked Sendable
    is a last resort. Document why the compiler cannot prove safety.
  6. Use
    sending
    parameters (SE-0430) for finer-grained isolation control.
  7. Use
    @preconcurrency import
    only for third-party libraries you cannot modify. Plan to remove it.
  1. 值类型(struct、enum)当所有存储属性都是
    Sendable
    时,会自动符合
    Sendable
  2. Actor隐式符合
    Sendable
  3. @MainActor
    类隐式符合
    Sendable
    ,请勿添加冗余的
    Sendable
    一致性。
  4. 非actor类:必须是
    final
    ,且所有存储属性为
    let
    并符合
    Sendable
  5. @unchecked Sendable
    是最后的手段,需说明编译器无法证明安全性的原因。
  6. 使用
    sending
    参数(SE-0430)实现更精细的隔离控制。
  7. 仅对无法修改的第三方库使用
    @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
    Task.isCancelled
    or call
    try Task.checkCancellation()
    in loops.
  • Use
    .task
    modifier in SwiftUI -- it handles cancellation on view disappear.
  • Use
    withTaskCancellationHandler
    for cleanup.
  • Cancel stored tasks in
    deinit
    or
    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
AsyncStream
to bridge callback/delegate APIs:
swift
let stream = AsyncStream<Location> { continuation in
    let delegate = LocationDelegate { location in
        continuation.yield(location)
    }
    continuation.onTermination = { _ in delegate.stop() }
    delegate.start()
}
Use
withCheckedContinuation
/
withCheckedThrowingContinuation
for single-value callbacks. Resume exactly once.
使用
AsyncStream
桥接回调/代理API:
swift
let stream = AsyncStream<Location> { continuation in
    let delegate = LocationDelegate { location in
        continuation.yield(location)
    }
    continuation.onTermination = { _ in delegate.stop() }
    delegate.start()
}
使用
withCheckedContinuation
/
withCheckedThrowingContinuation
处理单值回调,必须且只能恢复一次。

@Observable and Concurrency

@Observable与并发

  • @Observable
    classes should be
    @MainActor
    for view models.
  • Use
    @State
    to own an
    @Observable
    instance (replaces
    @StateObject
    ).
  • Use
    Observations { }
    (SE-0475) for async observation of
    @Observable
    properties as an
    AsyncSequence
    .
  • @Observable
    类作为视图模型时,应该标记为
    @MainActor
  • 使用
    @State
    持有
    @Observable
    实例(替代
    @StateObject
    )。
  • 使用
    Observations { }
    (SE-0475)通过
    AsyncSequence
    异步观察
    @Observable
    属性。

Common Mistakes

常见错误

  1. Blocking the main actor. Heavy computation on
    @MainActor
    freezes UI. Move to a
    @concurrent
    function.
  2. Unnecessary @MainActor. Network layers, data processing, and model code do not need
    @MainActor
    . Only UI-touching code does.
  3. Actors for stateless code. No mutable state means no actor needed. Use a plain struct or function.
  4. Actors for immutable data. Use a
    Sendable
    struct, not an actor.
  5. Task.detached without good reason. Loses priority, task-local values, and cancellation propagation.
  6. Forgetting task cancellation. Store
    Task
    references and cancel them, or use the
    .task
    view modifier.
  7. Retain cycles in Tasks. Use
    [weak self]
    when capturing
    self
    in long-lived stored tasks.
  8. Semaphores in async context.
    DispatchSemaphore.wait()
    in async code will deadlock. Use structured concurrency instead.
  9. Split isolation. Mixing
    @MainActor
    and
    nonisolated
    properties in one type. Isolate the entire type consistently.
  10. MainActor.run instead of static isolation. Prefer
    @MainActor func
    over
    await MainActor.run { }
    .
  1. 阻塞主actor。
    @MainActor
    上执行繁重计算会冻结UI,应移至
    @concurrent
    函数。
  2. 不必要的@MainActor。 网络层、数据处理和模型代码不需要
    @MainActor
    ,仅接触UI的代码需要。
  3. 为无状态代码使用Actor。 无可变状态则不需要Actor,使用普通struct或函数即可。
  4. 为不可变数据使用Actor。 使用符合
    Sendable
    的struct,而非Actor。
  5. 无正当理由使用Task.detached。 会丢失优先级、任务本地值和取消传播。
  6. 忘记任务取消。 存储Task引用并取消,或使用
    .task
    视图修饰符。
  7. Task中的循环引用。 在长期存储的Task中捕获
    self
    时使用
    [weak self]
  8. 异步上下文中的信号量。 在异步代码中使用
    DispatchSemaphore.wait()
    会导致死锁,应使用结构化并发替代。
  9. 拆分隔离。 在一个类型中混合
    @MainActor
    nonisolated
    属性,应保持整个类型的隔离一致性。
  10. 使用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
  • Sendable
    conformance is correct (no unjustified
    @unchecked
    )
  • Actor reentrancy is handled (no state assumptions across awaits)
  • @preconcurrency
    imports are documented with removal plan
  • Heavy work uses
    @concurrent
    , not
    @MainActor
  • .task
    modifier used in SwiftUI instead of manual Task management
  • 所有可变共享状态均已通过actor隔离
  • 无数据竞争(无未受保护的跨隔离访问)
  • 不再需要的任务已被取消
  • @MainActor上无阻塞调用
  • Actor内部无手动锁
  • Sendable一致性正确(无不合理的@unchecked)
  • 已处理Actor可重入性(不假设await期间状态不变)
  • @preconcurrency导入已记录移除计划
  • 繁重任务使用@concurrent而非@MainActor
  • SwiftUI中使用.task修饰符而非手动管理Task

Reference Material

参考资料

  • See
    references/swift-6-2-concurrency.md
    for detailed Swift 6.2 changes, patterns, and migration examples.
  • See
    references/approachable-concurrency.md
    for the approachable concurrency mode quick-reference guide.
  • See
    references/swiftui-concurrency.md
    for SwiftUI-specific concurrency guidance.
  • 查看
    references/swift-6-2-concurrency.md
    获取详细的Swift 6.2变更、模式和迁移示例。
  • 查看
    references/approachable-concurrency.md
    获取易用并发模式快速参考指南。
  • 查看
    references/swiftui-concurrency.md
    获取SwiftUI特定的并发指导。