首页/移动开发/swift-concurrency-6-2
S

swift-concurrency-6-2

by @affaan-mv
4.4(21)

Swift 6.2 易用并发:默认单线程,使用@concurrent实现并发。

swift-concurrencyasync/awaitactorsios-developmentswift-6.2GitHub
安装方式
npx skills add https://github.com/affaan-m/everything-claude-code --skill swift-concurrency-6-2
compare_arrows

Before / After 效果对比

1 组
使用前

Swift应用中的并发编程复杂且容易引入竞态条件和死锁,导致程序崩溃。难以编写安全高效的并发代码,影响用户体验。

使用后

借助Swift 6.2的并发特性,轻松编写安全可靠的并发代码,提升应用响应速度。有效避免并发问题,为用户提供流畅稳定的体验。

SKILL.md

Swift 6.2 Approachable Concurrency

Patterns for adopting Swift 6.2's concurrency model where code runs single-threaded by default and concurrency is introduced explicitly. Eliminates common data-race errors without sacrificing performance.

When to Activate

  • Migrating Swift 5.x or 6.0/6.1 projects to Swift 6.2
  • Resolving data-race safety compiler errors
  • Designing MainActor-based app architecture
  • Offloading CPU-intensive work to background threads
  • Implementing protocol conformances on MainActor-isolated types
  • Enabling Approachable Concurrency build settings in Xcode 26

Core Problem: Implicit Background Offloading

In Swift 6.1 and earlier, async functions could be implicitly offloaded to background threads, causing data-race errors even in seemingly safe code:

// 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 fixes this: async functions stay on the calling actor by default.

// 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)
    }
}

Core Pattern — Isolated Conformances

MainActor types can now conform to non-isolated protocols safely:

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()
    }
}

The compiler ensures the conformance is only used on the main 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
    }
}

Core Pattern — Global and Static Variables

Protect global/static state with 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 Default Inference Mode

Swift 6.2 introduces a mode where MainActor is inferred by default — no manual annotations needed:

// 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()
    }
}

This mode is opt-in and recommended for apps, scripts, and other executable targets.

Core Pattern — @concurrent for Background Work

When you need actual parallelism, explicitly offload with @concurrent:

Important: This example requires Approachable Concurrency build settings — SE-0466 (MainActor default isolation) and SE-0461 (NonisolatedNonsendingByDefault). With these enabled, extractSticker stays on the caller's actor, making mutable state access safe. Without these settings, this code has a data race — the compiler will flag it.

nonisolated final class PhotoProcessor {
    private 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
    }

    // Offload expensive work to concurrent thread pool
    @concurrent
    static func extractSubject(from data: Data) async -> Sticker { /* ... */ }
}

// Callers must await
let processor = PhotoProcessor()
processedPhotos[item.id] = await processor.extractSticker(data: data, with: item.id)

To use @concurrent:

  1. Mark the containing type as nonisolated
  2. Add @concurrent to the function
  3. Add async if not already asynchronous
  4. Add await at call sites

Key Design Decisions

DecisionRationale
Single-threaded by defaultMost natural code is data-race free; concurrency is opt-in
Async stays on calling actorEliminates implicit offloading that caused data-race errors
Isolated conformancesMainActor types can conform to protocols without unsafe workarounds
@concurrent explicit opt-inBackground execution is a deliberate performance choice, not accidental
MainActor default inferenceReduces boilerplate @MainActor annotations for app targets
Opt-in adoptionNon-breaking migration path — enable features incrementally

Migration Steps

  1. Enable in Xcode: Swift Compiler > Concurrency section in Build Settings
  2. Enable in SPM: Use SwiftSettings API in package manifest
  3. Use migration tooling: Automatic code changes via swift.org/migration
  4. Start with MainActor defaults: Enable inference mode for app targets
  5. Add @concurrent where needed: Profile first, then offload hot paths
  6. Test thoroughly: Data-race issues become compile-time errors

Best Practices

  • Start on MainActor — write single-threaded code first, optimize later
  • Use @concurrent only for CPU-intensive work — image processing, compression, complex computation
  • Enable MainActor inference mode for app targets that are mostly single-threaded
  • Profile before offloading — use Instruments to find actual bottlenecks
  • Protect globals with MainActor — global/static mutable state needs actor isolation
  • Use isolated conformances instead of nonisolated workarounds or @Sendable wrappers
  • Migrate incrementally — enable features one at a time in build settings

Anti-Patterns to Avoid

  • Applying @concurrent to every async function (most don't need background execution)
  • Using nonisolated to suppress compiler errors without understanding isolation
  • Keeping legacy DispatchQueue patterns when actors provide the same safety
  • Skipping model.availability checks in concurrency-related Foundation Models code
  • Fighting the compiler — if it reports a data race, the code has a real concurrency issue
  • Assuming all async code runs in the background (Swift 6.2 default: stays on calling actor)

When to Use

  • All new Swift 6.2+ projects (Approachable Concurrency is the recommended default)
  • Migrating existing apps from Swift 5.x or 6.0/6.1 concurrency
  • Resolving data-race safety compiler errors during Xcode 26 adoption
  • Building MainActor-centric app architectures (most UI apps)
  • Performance optimization — offloading specific heavy computations to background

用户评价 (0)

发表评价

效果
易用性
文档
兼容性

暂无评价

统计数据

安装量5.6K
评分4.4 / 5.0
版本
更新日期2026年8月6日
对比案例1 组

用户评分

4.4(21)
5
14%
4
48%
3
33%
2
5%
1
0%

为此 Skill 评分

0.0

兼容平台

🔧Claude Code
🔧OpenClaw
🔧OpenCode
🔧Codex
🔧Gemini CLI
🔧GitHub Copilot
🔧Amp
🔧Kimi CLI

时间线

创建2026年3月16日
最后更新2026年8月6日
🎁 Agent 知识卡片
调研问卷