Loading...
Loading...
Compare original and translation side by side
@concurrent@concurrent@concurrent@concurrent@concurrent@concurrent@MainActor@MainActornonisolated@concurrentSendableaxiom-swiftui-debuggingaxiom-swiftui-performance@MainActor@MainActornonisolated@concurrentSendableaxiom-swiftui-debuggingaxiom-swiftui-performanceApple's Guidance (WWDC 2025-268): "Your apps should start by running all of their code on the main thread, and you can get really far with single-threaded code."
苹果官方指导(WWDC 2025-268):「你的应用应从让所有代码运行在主线程开始,单线程代码就能满足很多场景的需求。」
Single-Threaded → Asynchronous → Concurrent → Actors
↓ ↓ ↓ ↓
Start here Hide latency Background Move data
(network) CPU work off main单线程 → 异步 → 并发 → Actors
↓ ↓ ↓ ↓
从这里开始 隐藏延迟 后台CPU任务 迁移数据
(网络操作) 处理 脱离主线程// ✅ Simple, single-threaded
class ImageModel {
var imageCache: [URL: Image] = [:]
func fetchAndDisplayImage(url: URL) throws {
let data = try Data(contentsOf: url) // Reads local file
let image = decodeImage(data)
view.displayImage(image)
}
func decodeImage(_ data: Data) -> Image {
// Decode image data
return Image()
}
}@MainActorBuild Settings → Swift Compiler — Language
→ "Default Actor Isolation" = Main Actor
Build Settings → Swift Compiler — Upcoming Features
→ "Approachable Concurrency" = Yes// ✅ 简单的单线程代码
class ImageModel {
var imageCache: [URL: Image] = [:]
func fetchAndDisplayImage(url: URL) throws {
let data = try Data(contentsOf: url) // 读取本地文件
let image = decodeImage(data)
view.displayImage(image)
}
func decodeImage(_ data: Data) -> Image {
// 解码图像数据
return Image()
}
}@MainActor构建设置 → Swift 编译器 — 语言
→ "默认 Actor 隔离" = 主线程
构建设置 → Swift 编译器 — 即将推出的功能
→ "渐进式并发" = 是// ❌ Blocks main thread until network completes
func fetchAndDisplayImage(url: URL) throws {
let (data, _) = try URLSession.shared.data(from: url) // ❌ Freezes UI!
let image = decodeImage(data)
view.displayImage(image)
}// ❌ 阻塞主线程直到网络请求完成
func fetchAndDisplayImage(url: URL) throws {
let (data, _) = try URLSession.shared.data(from: url) // ❌ 冻结 UI!
let image = decodeImage(data)
view.displayImage(image)
}// ✅ Suspends without blocking main thread
func fetchAndDisplayImage(url: URL) async throws {
let (data, _) = try await URLSession.shared.data(from: url) // ✅ Suspends here
let image = decodeImage(data) // ✅ Resumes here when data arrives
view.displayImage(image)
}await// ✅ 挂起函数但不阻塞主线程
func fetchAndDisplayImage(url: URL) async throws {
let (data, _) = try await URLSession.shared.data(from: url) // ✅ 在此处挂起
let image = decodeImage(data) // ✅ 数据到达后在此处恢复执行
view.displayImage(image)
}awaitclass ImageModel {
var url: URL = URL(string: "https://swift.org")!
func onTapEvent() {
Task { // ✅ Create task for user action
do {
try await fetchAndDisplayImage(url: url)
} catch {
displayError(error)
}
}
}
}class ImageModel {
var url: URL = URL(string: "https://swift.org")!
func onTapEvent() {
Task { // ✅ 为用户操作创建任务
do {
try await fetchAndDisplayImage(url: url)
} catch {
displayError(error)
}
}
}
}Task 1: [Fetch Image] → (suspend) → [Decode] → [Display]
Task 2: [Fetch News] → (suspend) → [Display News]
Main Thread Timeline:
[Fetch Image] → [Fetch News] → [Decode Image] → [Display Image] → [Display News]任务1:[获取图像] → (挂起) → [解码] → [显示]
任务2:[获取新闻] → (挂起) → [显示新闻]
主线程时间线:
[获取图像] → [获取新闻] → [解码图像] → [显示图像] → [显示新闻]decodeImage()func fetchAndDisplayImage(url: URL) async throws {
let (data, _) = try await URLSession.shared.data(from: url)
let image = decodeImage(data) // ❌ 200ms on main thread!
view.displayImage(image)
}decodeImage()func fetchAndDisplayImage(url: URL) async throws {
let (data, _) = try await URLSession.shared.data(from: url)
let image = decodeImage(data) // ❌ 在主线程耗时 200ms!
view.displayImage(image)
}@concurrent@concurrentfunc fetchAndDisplayImage(url: URL) async throws {
let (data, _) = try await URLSession.shared.data(from: url)
let image = await decodeImage(data) // ✅ Runs on background thread
view.displayImage(image)
}
@concurrent
func decodeImage(_ data: Data) async -> Image {
// ✅ Always runs on background thread pool
// Good for: image processing, file I/O, parsing
return Image()
}@concurrent@MainActorawaitfunc fetchAndDisplayImage(url: URL) async throws {
let (data, _) = try await URLSession.shared.data(from: url)
let image = await decodeImage(data) // ✅ 在后台线程运行
view.displayImage(image)
}
@concurrent
func decodeImage(_ data: Data) async -> Image {
// ✅ 始终在后台线程池运行
// 适用场景:图像处理、文件 I/O、解析
return Image()
}@concurrentawait@MainActornonisolatednonisolatednonisolated// ✅ Stays on caller's actor
nonisolated
func decodeImage(_ data: Data) -> Image {
// Runs on whatever actor called it
// Main actor → stays on main actor
// Background → stays on background
return Image()
}nonisolated@concurrentnonisolated// ✅ 保持在调用者的 actor 上
nonisolated
func decodeImage(_ data: Data) -> Image {
// 在调用它的 actor 上运行
// 主线程 actor → 保持在主线程 actor
// 后台线程 → 保持在后台线程
return Image()
}nonisolated@concurrent@concurrent@MainActor
class ImageModel {
var cachedImage: [URL: Image] = [:] // Main actor data
@concurrent
func decodeImage(_ data: Data, at url: URL) async -> Image {
if let image = cachedImage[url] { // ❌ Error: main actor access!
return image
}
// decode...
}
}func fetchAndDisplayImage(url: URL) async throws {
// ✅ Check cache on main actor BEFORE async work
if let image = cachedImage[url] {
view.displayImage(image)
return
}
let (data, _) = try await URLSession.shared.data(from: url)
let image = await decodeImage(data) // No URL needed now
view.displayImage(image)
}
@concurrent
func decodeImage(_ data: Data) async -> Image {
// ✅ No main actor access needed
return Image()
}@concurrent
func decodeImage(_ data: Data, at url: URL) async -> Image {
// ✅ Await to access main actor data
if let image = await cachedImage[url] {
return image
}
// decode...
}nonisolated
func decodeImage(_ data: Data) -> Image {
// ✅ No actor isolation, can call from anywhere
return Image()
}@concurrent@MainActor
class ImageModel {
var cachedImage: [URL: Image] = [:] // 主线程 actor 数据
@concurrent
func decodeImage(_ data: Data, at url: URL) async -> Image {
if let image = cachedImage[url] { // ❌ 错误:主线程 actor 访问!
return image
}
// 解码...
}
}func fetchAndDisplayImage(url: URL) async throws {
// ✅ 在异步工作前,在主线程 actor 上检查缓存
if let image = cachedImage[url] {
view.displayImage(image)
return
}
let (data, _) = try await URLSession.shared.data(from: url)
let image = await decodeImage(data) // 现在不需要 URL 了
view.displayImage(image)
}
@concurrent
func decodeImage(_ data: Data) async -> Image {
// ✅ 无需访问主线程 actor 数据
return Image()
}@concurrent
func decodeImage(_ data: Data, at url: URL) async -> Image {
// ✅ 通过 await 访问主线程 actor 数据
if let image = await cachedImage[url] {
return image
}
// 解码...
}nonisolated
func decodeImage(_ data: Data) -> Image {
// ✅ 无 actor 隔离,可以从任何位置调用
return Image()
}Main Thread: [UI] → (suspend) → [UI Update]
↓
Background Pool: [Task A] → [Task B] → [Task A resumes]
Thread 1 Thread 2 Thread 3主线程: [UI] → (挂起) → [UI 更新]
↓
后台线程池: [任务A] → [任务B] → [任务A 恢复]
线程1 线程2 线程3@MainActor
class ImageModel {
var cachedImage: [URL: Image] = [:]
let networkManager: NetworkManager = NetworkManager() // ❌ Also @MainActor
func fetchAndDisplayImage(url: URL) async throws {
// ✅ Background work...
let connection = await networkManager.openConnection(for: url) // ❌ Hops to main!
let data = try await connection.data(from: url)
await networkManager.closeConnection(connection, for: url) // ❌ Hops to main!
let image = await decodeImage(data)
view.displayImage(image)
}
}@MainActor
class ImageModel {
var cachedImage: [URL: Image] = [:]
let networkManager: NetworkManager = NetworkManager() // ❌ 同样是 @MainActor
func fetchAndDisplayImage(url: URL) async throws {
// ✅ 后台工作...
let connection = await networkManager.openConnection(for: url) // ❌ 切换到主线程!
let data = try await connection.data(from: url)
await networkManager.closeConnection(connection, for: url) // ❌ 切换到主线程!
let image = await decodeImage(data)
view.displayImage(image)
}
}// ✅ Move network state off main actor
actor NetworkManager {
var openConnections: [URL: Connection] = [:]
func openConnection(for url: URL) -> Connection {
if let connection = openConnections[url] {
return connection
}
let connection = Connection()
openConnections[url] = connection
return connection
}
func closeConnection(_ connection: Connection, for url: URL) {
openConnections.removeValue(forKey: url)
}
}
@MainActor
class ImageModel {
let networkManager: NetworkManager = NetworkManager()
func fetchAndDisplayImage(url: URL) async throws {
// ✅ Now runs mostly on background
let connection = await networkManager.openConnection(for: url)
let data = try await connection.data(from: url)
await networkManager.closeConnection(connection, for: url)
let image = await decodeImage(data)
view.displayImage(image)
}
}NetworkManageractor@MainActor class// ✅ 将网络状态移出主线程 actor
actor NetworkManager {
var openConnections: [URL: Connection] = [:]
func openConnection(for url: URL) -> Connection {
if let connection = openConnections[url] {
return connection
}
let connection = Connection()
openConnections[url] = connection
return connection
}
func closeConnection(_ connection: Connection, for url: URL) {
openConnections.removeValue(forKey: url)
}
}
@MainActor
class ImageModel {
let networkManager: NetworkManager = NetworkManager()
func fetchAndDisplayImage(url: URL) async throws {
// ✅ 现在大部分工作在后台运行
let connection = await networkManager.openConnection(for: url)
let data = try await connection.data(from: url)
await networkManager.closeConnection(connection, for: url)
let image = await decodeImage(data)
view.displayImage(image)
}
}NetworkManageractor@MainActor class@MainActor@MainActor@MainActor@MainActor// ✅ Value types copy when passed
let url = URL(string: "https://swift.org")!
Task {
// ✅ This is a COPY of url, not the original
// URLSession.shared.data runs on background automatically
let data = try await URLSession.shared.data(from: url)
}
// ✅ Original url unchanged by background task// ✅ 值类型传递时会复制
let url = URL(string: "https://swift.org")!
Task {
// ✅ 这是 url 的副本,而非原对象
// URLSession.shared.data 自动在后台运行
let data = try await URLSession.shared.data(from: url)
}
// ✅ 原 url 不受后台任务影响// ✅ Basic types
extension URL: Sendable {}
extension String: Sendable {}
extension Int: Sendable {}
extension Date: Sendable {}
// ✅ Collections of Sendable elements
extension Array: Sendable where Element: Sendable {}
extension Dictionary: Sendable where Key: Sendable, Value: Sendable {}
// ✅ Structs/enums with Sendable storage
struct Track: Sendable {
let id: String
let title: String
let duration: TimeInterval
}
enum PlaybackState: Sendable {
case stopped
case playing
case paused
}
// ✅ Main actor types
@MainActor class ImageModel {} // Implicitly Sendable (actor protects state)
// ✅ Actor types
actor NetworkManager {} // Implicitly Sendable (actor protects state)// ✅ 基础类型
extension URL: Sendable {}
extension String: Sendable {}
extension Int: Sendable {}
extension Date: Sendable {}
// ✅ 元素为 Sendable 的集合
extension Array: Sendable where Element: Sendable {}
extension Dictionary: Sendable where Key: Sendable, Value: Sendable {}
// ✅ 存储为 Sendable 属性的结构体/枚举
struct Track: Sendable {
let id: String
let title: String
let duration: TimeInterval
}
enum PlaybackState: Sendable {
case stopped
case playing
case paused
}
// ✅ 主线程 actor 类型
@MainActor class ImageModel {} // 隐式 Sendable(actor 保护状态)
// ✅ Actor 类型
actor NetworkManager {} // 隐式 Sendable(actor 保护状态)// ❌ Classes are NOT Sendable by default
class MyImage {
var width: Int
var height: Int
var pixels: [Color]
func scale(by factor: Double) {
// Mutates shared state
}
}
let image = MyImage()
let otherImage = image // ✅ Both reference SAME object
image.scale(by: 0.5) // ✅ Changes visible through otherImage!func scaleAndDisplay(imageName: String) {
let image = loadImage(imageName)
Task {
image.scale(by: 0.5) // Background task modifying
}
view.displayImage(image) // Main thread reading
// ❌ DATA RACE! Both threads could touch same object!
}@concurrent
func scaleAndDisplay(imageName: String) async {
let image = loadImage(imageName)
image.scale(by: 0.5) // ✅ All modifications on background
image.applyAnotherEffect() // ✅ Still on background
await view.displayImage(image) // ✅ Send to main actor AFTER modifications done
// ✅ Main actor now owns image exclusively
}@MainActor// ❌ 类默认不是 Sendable
class MyImage {
var width: Int
var height: Int
var pixels: [Color]
func scale(by factor: Double) {
// 修改共享状态
}
}
let image = MyImage()
let otherImage = image // ✅ 两者引用同一个对象
image.scale(by: 0.5) // ✅ 修改对 otherImage 可见!func scaleAndDisplay(imageName: String) {
let image = loadImage(imageName)
Task {
image.scale(by: 0.5) // 后台任务修改对象
}
view.displayImage(image) // 主线程读取对象
// ❌ 数据竞争!两个线程可能同时访问同一个对象!
}@concurrent
func scaleAndDisplay(imageName: String) async {
let image = loadImage(imageName)
image.scale(by: 0.5) // ✅ 所有修改在后台完成
image.applyAnotherEffect() // ✅ 仍在后台
await view.displayImage(image) // ✅ 修改完成后再传递到主线程 actor
// ✅ 主线程 actor 现在独占该对象
}@MainActorawaitfunc fetchAndDisplayImage(url: URL) async throws {
let (data, _) = try await URLSession.shared.data(from: url)
// ↑ Sendable ↑ Sendable (crosses to background)
let image = await decodeImage(data)
// ↑ data crosses to background (must be Sendable)
// ↑ image returns to main (must be Sendable)
}awaitfunc fetchAndDisplayImage(url: URL) async throws {
let (data, _) = try await URLSession.shared.data(from: url)
// ↑ Sendable ↑ Sendable(切换到后台)
let image = await decodeImage(data)
// ↑ data 切换到后台(必须是 Sendable)
// ↑ image 返回主线程(必须是 Sendable)
}// ✅ Enum (no associated values)
private enum PlaybackState: Sendable {
case stopped
case playing
case paused
}
// ✅ Struct (all properties Sendable)
struct Track: Sendable {
let id: String
let title: String
let artist: String?
}
// ✅ Enum with Sendable associated values
enum Result: Sendable {
case success(data: Data)
case failure(error: Error) // Error is Sendable
}// ✅ 枚举(无关联值)
private enum PlaybackState: Sendable {
case stopped
case playing
case paused
}
// ✅ 结构体(所有属性都是 Sendable)
struct Track: Sendable {
let id: String
let title: String
let artist: String?
}
// ✅ 关联值为 Sendable 的枚举
enum Result: Sendable {
case success(data: Data)
case failure(error: Error) // Error 是 Sendable
}nonisolated@MainActornonisolated func delegate(_ param: SomeType) {
// ✅ Step 1: Capture delegate parameter values BEFORE Task
let value = param.value
let status = param.status
// ✅ Step 2: Task hop to MainActor
Task { @MainActor in
// ✅ Step 3: Safe to access self (we're on MainActor)
self.property = value
print("Status: \(status)")
}
}nonisolatedselfTask { @MainActor in }nonisolated@MainActornonisolated func delegate(_ param: SomeType) {
// ✅ 步骤1:在创建 Task 前捕获代理参数值
let value = param.value
let status = param.status
// ✅ 步骤2:切换到 MainActor 的 Task
Task { @MainActor in
// ✅ 步骤3:安全访问 self(当前在 MainActor)
self.property = value
print("状态:\(status)")
}
}nonisolatedTask { @MainActor in }selfclass MusicPlayer {
private var progressTask: Task<Void, Never>?
func startMonitoring() {
progressTask = Task { [weak self] in // ✅ Weak capture
guard let self = self else { return }
while !Task.isCancelled {
await self.updateProgress()
}
}
}
deinit {
progressTask?.cancel()
}
}class MusicPlayer {
private var progressTask: Task<Void, Never>?
func startMonitoring() {
progressTask = Task { [weak self] in // ✅ 弱引用捕获
guard let self = self else { return }
while !Task.isCancelled {
await self.updateProgress()
}
}
}
deinit {
progressTask?.cancel()
}
}@concurrent
func decodeImage(_ data: Data) async -> Image {
// ✅ Always runs on background thread pool
// Good for: image processing, file I/O, JSON parsing
return Image()
}
// Usage
let image = await decodeImage(data) // Automatically offloads@concurrent
func decodeImage(_ data: Data) async -> Image {
// ✅ 始终在后台线程池运行
// 适用场景:图像处理、文件 I/O、JSON 解析
return Image()
}
// 使用方式
let image = await decodeImage(data) // 自动卸载到后台protocol Exportable {
func export()
}
class PhotoProcessor {
@MainActor
func exportAsPNG() {
// Export logic requiring UI access
}
}
// ✅ Conform with explicit isolation
extension StickerModel: @MainActor Exportable {
func export() {
photoProcessor.exportAsPNG() // ✅ Safe: both on MainActor
}
}protocol Exportable {
func export()
}
class PhotoProcessor {
@MainActor
func exportAsPNG() {
// 需要访问 UI 的导出逻辑
}
}
// ✅ 显式指定隔离方式遵循协议
extension StickerModel: @MainActor Exportable {
func export() {
photoProcessor.exportAsPNG() // ✅ 安全:两者都在 MainActor
}
}var currentTime: TimeInterval {
get async {
// ✅ Cache reference for atomic snapshot
guard let player = player else { return 0 }
return player.currentTime
}
}var currentTime: TimeInterval {
get async {
// ✅ 缓存引用以实现原子快照
guard let player = player else { return 0 }
return player.currentTime
}
}@MainActor
class PlayerViewModel: ObservableObject {
@Published var currentTrack: Track?
@Published var isPlaying: Bool = false
func play(_ track: Track) async {
// Already on MainActor
self.currentTrack = track
self.isPlaying = true
}
}@MainActor
class PlayerViewModel: ObservableObject {
@Published var currentTrack: Track?
@Published var isPlaying: Bool = false
func play(_ track: Track) async {
// 已在 MainActor
self.currentTrack = track
self.isPlaying = true
}
}actor DataFetcher {
let modelContainer: ModelContainer
func fetchAllTracks() async throws -> [Track] {
let context = ModelContext(modelContainer)
let descriptor = FetchDescriptor<Track>(
sortBy: [SortDescriptor(\.title)]
)
return try context.fetch(descriptor)
}
}
@MainActor
class TrackViewModel: ObservableObject {
@Published var tracks: [Track] = []
func loadTracks() async {
let fetchedTracks = try await fetcher.fetchAllTracks()
self.tracks = fetchedTracks // Back on MainActor
}
}actor DataFetcher {
let modelContainer: ModelContainer
func fetchAllTracks() async throws -> [Track] {
let context = ModelContext(modelContainer)
let descriptor = FetchDescriptor<Track>(
sortBy: [SortDescriptor(\.title)]
)
return try context.fetch(descriptor)
}
}
@MainActor
class TrackViewModel: ObservableObject {
@Published var tracks: [Track] = []
func loadTracks() async {
let fetchedTracks = try await fetcher.fetchAllTracks()
self.tracks = fetchedTracks // 返回 MainActor
}
}actor CoreDataFetcher {
func fetchTracksID(genre: String) async throws -> [String] {
let context = persistentContainer.newBackgroundContext()
var trackIDs: [String] = []
try await context.perform {
let request = NSFetchRequest<CDTrack>(entityName: "Track")
request.predicate = NSPredicate(format: "genre = %@", genre)
let results = try context.fetch(request)
trackIDs = results.map { $0.id } // Extract IDs before leaving context
}
return trackIDs // Lightweight, Sendable
}
}actor CoreDataFetcher {
func fetchTracksID(genre: String) async throws -> [String] {
let context = persistentContainer.newBackgroundContext()
var trackIDs: [String] = []
try await context.perform {
let request = NSFetchRequest<CDTrack>(entityName: "Track")
request.predicate = NSPredicate(format: "genre = %@", genre)
let results = try context.fetch(request)
trackIDs = results.map { $0.id } // 离开上下文前提取 ID
}
return trackIDs // 轻量级,Sendable
}
}actor DataImporter {
func importRecords(_ records: [RawRecord], onProgress: @MainActor (Int, Int) -> Void) async throws {
let chunkSize = 1000
let context = ModelContext(modelContainer)
for (index, chunk) in records.chunked(into: chunkSize).enumerated() {
for record in chunk {
context.insert(Track(from: record))
}
try context.save()
let processed = (index + 1) * chunkSize
await onProgress(min(processed, records.count), records.count)
if Task.isCancelled { throw CancellationError() }
}
}
}actor DataImporter {
func importRecords(_ records: [RawRecord], onProgress: @MainActor (Int, Int) -> Void) async throws {
let chunkSize = 1000
let context = ModelContext(modelContainer)
for (index, chunk) in records.chunked(into: chunkSize).enumerated() {
for record in chunk {
context.insert(Track(from: record))
}
try context.save()
let processed = (index + 1) * chunkSize
await onProgress(min(processed, records.count), records.count)
if Task.isCancelled { throw CancellationError() }
}
}
}actor DatabaseQueryExecutor {
let dbQueue: DatabaseQueue
func fetchUserWithPosts(userId: String) async throws -> (user: User, posts: [Post]) {
return try await dbQueue.read { db in
let user = try User.filter(Column("id") == userId).fetchOne(db)!
let posts = try Post
.filter(Column("userId") == userId)
.order(Column("createdAt").desc)
.limit(100)
.fetchAll(db)
return (user, posts)
}
}
}actor DatabaseQueryExecutor {
let dbQueue: DatabaseQueue
func fetchUserWithPosts(userId: String) async throws -> (user: User, posts: [Post]) {
return try await dbQueue.read { db in
let user = try User.filter(Column("id") == userId).fetchOne(db)!
let posts = try Post
.filter(Column("userId") == userId)
.order(Column("createdAt").desc)
.limit(100)
.fetchAll(db)
return (user, posts)
}
}
}Starting new feature?
└─ Is UI responsive with all operations on main thread?
├─ YES → Stay single-threaded (Step 1)
└─ NO → Continue...
└─ Do you have high-latency operations? (network, file I/O)
├─ YES → Add async/await (Step 2)
└─ NO → Continue...
└─ Do you have CPU-intensive work? (Instruments shows main thread busy)
├─ YES → Add @concurrent or nonisolated (Step 3)
└─ NO → Continue...
└─ Is main actor contention causing slowdowns?
└─ YES → Extract subsystem to actor (Step 4)
Error: "Main actor-isolated property accessed from nonisolated context"
├─ In delegate method?
│ └─ Pattern 2: Value Capture Before Task
├─ In async function?
│ └─ Add @MainActor or call from Task { @MainActor in }
└─ In @concurrent function?
└─ Move access to caller, use await, or make nonisolated
Error: "Type does not conform to Sendable"
├─ Enum/struct with Sendable properties?
│ └─ Add `: Sendable`
└─ Class?
└─ Make @MainActor or keep non-Sendable (don't share concurrently)
Want to offload work to background?
├─ Always background (image processing)?
│ └─ Use @concurrent (Swift 6.2+)
├─ Caller decides?
│ └─ Use nonisolated
└─ Too much main actor state?
└─ Extract to actor启动新功能?
└─ 所有操作在主线程时 UI 是否响应流畅?
├─ 是 → 保持单线程(步骤1)
└─ 否 → 继续...
└─ 是否存在高延迟操作?(网络、文件 I/O)
├─ 是 → 添加 async/await(步骤2)
└─ 否 → 继续...
└─ 是否存在 CPU 密集型工作?(Instruments 显示主线程繁忙)
├─ 是 → 添加 @concurrent 或 nonisolated(步骤3)
└─ 否 → 继续...
└─ 主线程 Actor 资源竞争是否导致性能下降?
└─ 是 → 将子系统提取为 Actor(步骤4)
错误:"Main actor-isolated property accessed from nonisolated context"
├─ 是否在代理方法中?
│ └─ 使用模式2:创建 Task 前捕获值
├─ 是否在异步函数中?
│ └─ 添加 @MainActor 或在 Task { @MainActor in } 中调用
└─ 是否在 @concurrent 函数中?
└─ 将访问逻辑移到调用者处、使用 await 或标记为 nonisolated
错误:"Type does not conform to Sendable"
├─ 是否是属性均为 Sendable 的枚举/结构体?
│ └─ 添加 `: Sendable`
└─ 是否是类?
└─ 标记为 @MainActor 或保持非 Sendable(不要并发共享)
想要将工作卸载到后台?
├─ 是否始终要在后台运行?(如图像处理)
│ └─ 使用 @concurrent(Swift 6.2+)
├─ 是否由调用者决定运行位置?
│ └─ 使用 nonisolated
└─ 主线程 Actor 状态过多?
└─ 提取为 ActorBuild Settings → Swift Compiler — Language
→ "Default Actor Isolation" = Main Actor
→ "Approachable Concurrency" = Yes
Build Settings → Swift Compiler — Concurrency
→ "Strict Concurrency Checking" = Complete构建设置 → Swift 编译器 — 语言
→ "默认 Actor 隔离" = 主线程
→ "渐进式并发" = 是
构建设置 → Swift 编译器 — 并发
→ "严格并发检查" = 完整// ❌ Premature optimization
@concurrent
func addNumbers(_ a: Int, _ b: Int) async -> Int {
return a + b // ❌ Trivial work, concurrency adds overhead
}
// ✅ Keep simple
func addNumbers(_ a: Int, _ b: Int) -> Int {
return a + b
}// ❌ 过早优化
@concurrent
func addNumbers(_ a: Int, _ b: Int) async -> Int {
return a + b // ❌ 琐碎工作,并发会增加开销
}
// ✅ 保持简单
func addNumbers(_ a: Int, _ b: Int) -> Int {
return a + b
}// ❌ Memory leak
progressTask = Task {
while true {
await self.update() // ❌ Strong capture
}
}
// ✅ Weak capture
progressTask = Task { [weak self] in
guard let self = self else { return }
// ...
}// ❌ 内存泄漏
progressTask = Task {
while true {
await self.update() // ❌ 强引用
}
}
// ✅ 弱引用
progressTask = Task { [weak self] in
guard let self = self else { return }
// ...
}// ❌ Don't do this
actor MyViewModel: ObservableObject { // ❌ UI code should be @MainActor!
@Published var state: State // ❌ Won't work correctly
}
// ✅ Do this
@MainActor
class MyViewModel: ObservableObject {
@Published var state: State
}// ❌ 切勿这样做
actor MyViewModel: ObservableObject { // ❌ UI 代码应使用 @MainActor!
@Published var state: State // ❌ 无法正常工作
}
// ✅ 正确做法
@MainActor
class MyViewModel: ObservableObject {
@Published var state: State
}@concurrentnonisolated@concurrentnonisolated