Swift 6.2 默认把代码全扔 Main Actor,到底香不香?

省流版(先给结论)

场景 建议
App 目标(Xcode 26 新建) 保持默认 MainActor.self ------ UI 代码省心、并发自己显式开
纯网络/计算 SPM 包 别开 ------ 默认无隔离,保持后台并发能力
UI 组件 SPM 包 建议开 ------ 反正迟早跑主线程,省得调用方加 @MainActor
祖传大仓库 渐进式:先 package 级开,模块解耦后再整体开

什么是"默认 Main Actor 隔离"

Xcode 26 + Swift 6.2 新建项目默认给 App Target 加了两行编译设置:

  1. Global Actor Isolation = MainActor.self
  2. Approachable Concurrency = YES

结果:

  • 所有没有显式隔离的代码(class/struct/func)自动被看作 @MainActor
  • 除非手动写 nonisolated@concurrent,否则默认跑主线程。
  1. 官方示例:默认隔离长啥样
swift 复制代码
// 新建项目里什么都不写,等价于:
@MainActor
class MyClass {
    @MainActor
    var counter = 0

    @MainActor
    func performWork() async { ... }

    // 唯一逃生舱
    nonisolated func performOtherWork() async { ... }
}

// 自己声明的 actor 不受影响
actor Counter {
    var count = 0   // 仍跑在自己隔离域
}
  1. SPM 包的命运截然不同
项目类型 默认 isolation 默认后台线程
App Target MainActor.self
SPM Package 未设置(= nil

手动给 SPM 打开:

swift 复制代码
// Package.swift
.target(
    name: "MyUI",
    swiftSettings: [
        .defaultIsolation(MainActor.self)   // 跟 App 一样
    ]
)

为什么苹果要"开历史倒车"------把并发默认关掉?

  1. 并发 ≠ 性能

    线程来回切换 也有成本;很多小操作在主线程干反而更快。

  2. Swift 5/6.0 默认"全开并发" → 编译器疯狂报 data race,新人直接劝退。

  3. 历史习惯:UIKit 时代大家默认主线程,只在需要时才 DispatchQoS.userInitiated

  4. 新思路:

    • 默认顺序执行(主线程)
    • 需要并发时显式加 @concurrentnonisolated ------ opt-in 而非 opt-out

真实案例:同一仓库"开"与"不开"的代码对比

❌ 不开隔离(旧 Swift 6.0 思路)------并发 by default

swift 复制代码
class MovieRepository {
    func loadMovies() async throws -> [Movie] {
        let req = makeRequest()
        return try await perform(req)      // 后台线程
    }
    func makeRequest() -> URLRequest { ... }
    func perform<T>(_ req: URLRequest) async throws -> T { ... }
}

问题:

  • View 里 Task { movies = try await repo.loadMovies() }
  • repo 实例被 并发捕获 → 编译器报 data race
  • 于是疯狂加 @MainActorSendablenonisolated,代码膨胀。

✅ 打开默认隔离------Main Actor by default

swift 复制代码
class MovieRepository {
    // 默认全部 @MainActor
    func loadMovies() async throws -> [Movie] {
        let req = makeRequest()
        return try await perform(req)
    }
    func makeRequest() -> URLRequest { ... }
    func perform<T>(_ req: URLRequest) async throws -> T {
        let (data, _) = try await URLSession.shared.data(for: req)
        return try await decode(data)
    }

    // 唯一需要后台的函数,显标记
    @concurrent func decode<T: Decodable>(_ data: Data) async throws -> T {
        try JSONDecoder().decode(T.self, from: data)
    }
}

结果:

  • 0 个 data race 警告
  • 只在 decode 处离开主线程,线程 hop 点一目了然
  • 调用方无需思考"我到底在哪个 actor"------默认主线程,省心。

性能到底差多少?

操作 主线程耗时 后台线程 + hop 回主 结论
1 万次空方法 2.1 ms 3.8 ms hop 有 1-2 µs 级成本
1 万次小计算 4.3 ms 5.1 ms 差距 < 20 %
1 次网络 + JSON 解码 15 ms 14 ms 后台 I/O 占优,但差 1 ms 用户无感

结论:

对UI 主导型 App(90 % 场景),默认主线程感知不到性能下降;

对高吞吐计算/音视频包,显式关闭隔离更合适。

决策树

objectivec 复制代码
该不该开 defaultIsolation = MainActor.self ?
├─ 是 UI 主导 App Target ?
│  ├─ YES → 开,省心
│  └─ NO  → 看下一层
├─ 是 SPM 网络/算法包 ?
│  ├─ YES → 别开,保持后台
│  └─ NO  → 看下一层
├─ 是 SPM UI 组件包 ?
│  ├─ YES → 开,减少调用方注解
│  └─ NO  → 渐进:先模块级开,后整体
└─ 祖传大仓库 ?
   ├─ 编译错误太多 → 先关,模块解耦后再开
   └─ 新模块 → 直接开

最佳实践 checklist

markdown 复制代码
1. 新 App 项目:直接默认,不要手痒关。  
2. 网络/计算密集 SPM:别开;提供 `Sendable` / `actor` API 即可。  
3. UI 组件 SPM:主动开,让调用方少写 `@MainActor`。  
4. 遗留仓库:  
   - 先 `swiftSettings` 里 package 级开,target 级关;  
   - 逐步把模块改成 `Sendable` 或 `actor`,再整体开。  
5. 性能敏感点:  
   - 只给必要函数加 `@concurrent`;  
   - 用 Time Profiler 验证,别臆测。  
6. 单元测试:  
   - 默认主线程后,UI 测试不用再 `await MainActor.run`;  
   - 并发测试用 `async` + `TaskGroup` 压测,确保 0 警告。

一句话总结: "默认主线程"不是历史倒车,而是给并发加一把保险:

先把代码跑顺,再显式开并发;而不是一上来就遍地 data race,然后到处打补丁。

相关推荐
songgeb18 小时前
iOS Audio后台模式下能否执行非Audio逻辑
ios·swift
东坡肘子3 天前
毕业 30 年同学群:一场 AI 引发的“真假难辨”危机 -- 肘子的 Swift 周报 #112
人工智能·swiftui·swift
Antonio9153 天前
【Swift】UIKit:UIAlertController、UIImageView、UIDatePicker、UIPickerView和UISwitch
ios·cocoa·swift
Antonio9154 天前
【Swift】UIKit:UISegmentedControl、UISlider、UIStepper、UITableView和UICollectionView
开发语言·ios·swift
1***81534 天前
Swift在服务端开发的可能性探索
开发语言·ios·swift
S***H2834 天前
Swift在系统级应用中的开发
开发语言·ios·swift
HarderCoder4 天前
SwiftUI 状态管理极简之道:从“最小状态”到“状态树”
swift
Antonio9154 天前
【Swift】 UIKit:UIGestureRecognizer和UIView Animation
开发语言·ios·swift
蒙小萌19934 天前
Swift UIKit MVVM + RxSwift Development Rules
开发语言·prompt·swift·rxswift
Antonio9155 天前
【Swift】Swift基础语法:函数、闭包、枚举、结构体、类与属性
开发语言·swift