过去两周,知乎和开发者社区里连着转了几篇讲 Swift 6.2 并发的长文,热度最高的是 SwiftLee 博主 Antoine van der Lee 的两篇深度拆解——一篇讲 Approachable Concurrency,一篇讲 Sendable,标题里写着「150K 开发者都在聊」。知乎评论区里被问得最多的问题出奇一致:「我这项目里的 @MainActor 还要不要?」「我去年照教程写的并发代码,现在算不算过时写法?」
这个问题问得正是时候。8 月 25 日凌晨,苹果面向开发者与公测用户同步推送了 iOS 27 Beta 7 与 Public Beta 5,版本号 24A5424a;按爱思助手的推算,iOS 27 正式版将在秋季发布会结束后于 9 月 15 日凌晨正式上线。知乎发布会具体日期目前社区流传的口径在 9 月 8 日到 10 日之间。微博接下来这一个月,是很多团队升级工具链、赶适配、顺手把 Swift 6 迁移提上日程的窗口期。

先说结论:你写的并发代码没有「过时」,但有三个默认值确实被翻了。它们不会自动影响还停在 Swift 5 模式的老项目,可只要你开新项目、或者正在迁移途中,写法的差别非常大。这篇文章把三处翻转、对应的决策点、以及三种项目状态各自的行动清单一次讲清。
翻转一:nonisolated async 从「默认跳后台」变成「跟着调用者走」
这是被讨论得最多的一处。
老行为是这样的:你写了一个 nonisolated 的 async 方法,本意是个轻量辅助函数,结果只要一 await,编译器就把执行丢到全局线程池(cooperative executor)。你在 @MainActor 的 ViewModel 里调它,哪怕它什么都没干,执行也会立刻离开主线程;想更新 UI,得手动 await MainActor.run 跳回来。转译文章里举过一个真实案例:一个 ViewModel 里 12 个 nonisolated async 辅助方法,每个内部都要 await MainActor.run 跳回主线程,代码读起来像迷宫。文档对这种行为的解释只有一句:「这是预期行为」。
Swift 6.2 的 Approachable Concurrency 把这个默认翻了过来。开启之后(对应构建设置里的 APPROACHABLE_CONCURRENCY,底层是 NonisolatedNonsendingByDefault),nonisolated async 方法不再默认跳线程,而是留在调用者所在的线程上执行;await 结束之后,还会回到调用者的上下文。知乎换句话说,nonisolated 的含义从「不属于任何 actor,去后台跑」变成了「不属于任何 actor,但跟着你走」——和同步方法的行为对齐了。
那真需要后台执行怎么办?用新增的 @concurrent 属性,显式声明「不管谁调我,都去全局并发池跑」,典型场景是 CPU 密集计算、文件 IO、网络请求。@concurrent 自带 nonisolated 含义,不用重复写。
一句话总结这个翻转:默认跟着调用者走,显式声明才去后台。过去是反过来的。
翻转二:新项目默认全员 MainActor,思路从「加注解」变成「摘注解」
Xcode 26 起,新建项目的 app target 默认启用 Default Actor Isolation:整个 target 里的代码自动隔离到 main actor,除非你显式退出。知乎

对习惯手写 @MainActor 的人来说,这是一次思维反转。过去的问题是「这个类要不要加 @MainActor」,现在的问题是「哪些代码要用 nonisolated 或 @concurrent 从主线程上摘出去」。SwiftLee 在指南里给的建议很直接:新项目里大部分情况下不需要手动加 @MainActor,编译器已经替你做了;你真正要花心思的是找出那些不需要主线程的纯计算、文件 IO、解析逻辑,把它们 opt-out。
这里藏着一个新坑:默认全员主线程之后,「忘了摘出去」的代价是重活默默跑在主线程上,跟 UI 抢时间,表现为掉帧和卡顿,而且编译器不会提醒你——因为从隔离规则上看,这段代码完全合法。所以新项目迁移这套默认值,收益是少写一堆注解,成本是要重新审一遍「什么活不该在主线程干」。
老项目不受影响。如果你的工程还在 Swift 5 模式,或者明确关掉了默认隔离,@MainActor 仍然是你保证 UI 更新在主线程的核心手段,这条规则没有变。
翻转三:Sendable 报错不再只看类型,还看值的生命周期
Sendable 是 Swift 6 迁移里劝退最多人的地方:编译器突然说你的类型不能跨并发域传递,改了几轮错误越改越多,很多人干脆把严格并发检查关掉,眼不见为净。
但把机制拆开看,Sendable 本身简单得惊人——它是个空协议,定义里没有任何方法要求,只是一个标记:告诉编译器「这个类型可以安全跨线程传递」,编译器负责验证你说的是不是真的。知乎值类型加成员都合规,编译器自动放行;class 默认不行,因为引用传过去两边都能改。
真正值得知道的新变化是「区域隔离」(region-based isolation):编译器不再只盯着类型合不合规,还会看值的生命周期。如果一个不合规的值传出去之后外面再也没人碰它,传递照样放行;传完又用了一次,立刻报错。配合 sending 关键字,API 可以显式声明「这个东西交给我之后你不能再用了」,让非 Sendable 类型也能安全地跨域传递。
对于必须是 class 的场景(比如要对接 UIKit),优先级顺序值得记住:优先不可变的 final class(所有属性 let);其次隔离到全局 Actor(标了 @MainActor 的 class 会隐式获得 Sendable,这就是 ViewModel 加了 @MainActor 之后可以随便传的原因);再次用 Synchronization 框架里的 Mutex 替代老的「锁 + @unchecked」写法;@unchecked Sendable 是最后手段——它等于跟编译器说「别查了,我自己保证」,今天安全,明天有人加了个不加锁的属性,数据竞争就悄悄回来了,编译器一个字都不会提醒。
新代码的顺序:值类型 → actor → Mutex → 实在不行才 @unchecked。知乎
决策清单:@MainActor 什么时候删、什么时候留
把上面三个翻转落到日常编码,决策点其实不多:
第一,看你的项目模式。新项目(Xcode 26/27 默认模板)里,ViewModel 这类 UI 逻辑类不用再手写类级 @MainActor,默认已经隔离;反而要给不需要主线程的方法补 nonisolated。老项目(非默认隔离)里,@MainActor 一个都别删,它仍是主线程的保证。
第二,标注范围的选择。@MainActor 可以标在属性、方法、类、闭包四个层级。知乎原则是范围越小并发性能越好,但实操上,纯 UI 逻辑的类直接标类级最省事;只有「大部分逻辑在后台、最后一步更新 UI」的场景,才值得用闭包级或方法级。
第三,MainActor.run 和 Task { @MainActor in } 的分工。前者只把闭包内部切到主线程,是精确的切换点。知乎后者让整个任务都在主线程跑。只有几行赋值要上主线程,用 MainActor.run;整个任务都是 UI 更新,用 Task。

第四,Swift 5 模式的老项目要单独提防一个坑:@MainActor 标注的同步方法,如果被后台线程同步调用,实际会在后台线程执行——编译器在 Swift 5 模式下不会拦你,UI 偶发崩溃就是这么来的。排查方向:所有 @MainActor 同步方法的调用链,要么改成 async 调用,要么升 Swift 6 模式让编译器接管。
三种项目,三种动作
还没迁移的老项目:不用焦虑。这三个翻转都要等你打开语言模式开关才会生效。当下要做的事只有一件——团队里有人在用 Xcode 26/27 建新工程、或者从网上复制新写法混进老工程之前,先确认两种默认值下的行为差异,混写是迁移期最容易出的事故。想预热的话,把 SWIFT_STRICT_CONCURRENCY 从 minimal 调到 targeted,只对用了 async/await 的代码做完整检查,这是社区公认的渐进迁移甜蜜点。知乎
正在迁移的项目:顺序比速度重要。先开 Swift 6 语言模式,看一遍报错总量心里有数;优先修 @MainActor 相关错误,它们大多是「同步方法在非隔离上下文被调用」,修法就是改 async 或者显式 MainActor.run。知乎然后再逐个给 ViewModel 和 UI 类补隔离标注。迁移完用 Instruments 的 Swift Concurrency 工具查一遍主线程负载,确认没有重活被默认隔离「顺带」留在主线程上。
新项目:享受默认隔离带来的简洁,但开工前先列一张「不上主线程清单」——网络、解析、加解密、大循环,这几类从一开始就用 @concurrent 或独立 actor 隔离,别等性能出问题了再回头摘。
为什么是现在
iOS 27 正式版预计 9 月 15 日凌晨上线,RC 候选版最早 9 月 1 日就可能推送。知乎 Xcode 27 beta 还在高频迭代,已经有开发者遇到「beta 编译的项目没法上架 App Store」这类实打实的问题。微博接下来三周是提交和工具链升级的高峰,也是「要不要趁这次把 Swift 6 迁了」这个决策集中出现的窗口。8 月这波讨论热度不是偶然——SwiftLee 的两篇长文、知乎上连续几篇解读、B 站上苹果官方 WWDC 并发课程的持续播放量,都指向同一件事:迁移的人多了,撞上新旧默认值差异的人也就多了。哔哩哔哩

值得继续盯的信号有三个:9 月 1 日前后是否还有 beta 8,还是 beta 7 直接转 RC;Xcode 27 正式版的新项目模板里,默认隔离和 Approachable Concurrency 的最终开启状态;以及你自己项目迁移后第一个版本的主线程性能数据。
一句话判断:Swift 6.2 拆掉的不是并发安全,而是「防御性跳线程」。如果你的项目正好要在这个窗口迁移,先改的不是代码里的注解,是脑子里那张「哪行代码跑在哪个线程」的地图——默认值变了,地图也得换。