帮助开发者理解 Swift 6.2 并发模型变化与安全使用方式。
复制安装指令,让 AI 自动完成配置 · 推荐新手
请帮我安装 askskill 上的 "swift-concurrency-6-2" 技能: 1. 下载 https://raw.githubusercontent.com/affaan-m/ECC/main/skills/swift-concurrency-6-2/SKILL.md 2. 保存为 ~/.claude/skills/swift-concurrency-6-2/SKILL.md 3. 装好后重载技能,告诉我可以用了
请用通俗语言解释 Swift 6.2 的 Approachable Concurrency,包括默认单线程、@concurrent 的作用,以及 isolated conformances 对主线程类型意味着什么,并给一个简单示例。
一份结构清晰的中文说明,概括核心概念并附带示例代码。
我有一段旧的 Swift 并发代码,请根据 Swift 6.2 的并发模型帮我重构,指出哪些逻辑应保持默认隔离,哪些任务适合用 @concurrent 显式放到后台执行,并说明原因。
重构建议、更新后的代码示例,以及逐项修改原因说明。
请检查这段 Swift 代码中主线程相关类型的协议实现是否适合使用 isolated conformances,并指出潜在的线程安全问题与修复方案。
对协议实现的审查结果,包含风险点、修复建议和示例写法。
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.
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)
}
}
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
}
}
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
}
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.
When you need actual parallelism, explicitly offload with @concurrent:
…