当前位置:
AIGC文章详情

Swift 6.2 把三个默认值翻了:nonisolated async 不再跳线程,Xcode 新项目默认全员 MainActor,删不删 @MainActor 先看这篇

源自273位全网作者

08-26 10:01

过去两周,知乎和开发者社区里连着转了几篇讲 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 6.2 把三个默认值翻了:nonisolated async 不再跳线程,Xcode 新项目默认全员 MainActor,删不删 @MainActor 先看这篇

先说结论:你写的并发代码没有「过时」,但有三个默认值确实被翻了。它们不会自动影响还停在 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,除非你显式退出。知乎

Swift 6.2 把三个默认值翻了:nonisolated async 不再跳线程,Xcode 新项目默认全员 MainActor,删不删 @MainActor 先看这篇

对习惯手写 @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 6.2 把三个默认值翻了:nonisolated async 不再跳线程,Xcode 新项目默认全员 MainActor,删不删 @MainActor 先看这篇

第四,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 并发课程的持续播放量,都指向同一件事:迁移的人多了,撞上新旧默认值差异的人也就多了。哔哩哔哩

Swift 6.2 把三个默认值翻了:nonisolated async 不再跳线程,Xcode 新项目默认全员 MainActor,删不删 @MainActor 先看这篇

值得继续盯的信号有三个:9 月 1 日前后是否还有 beta 8,还是 beta 7 直接转 RC;Xcode 27 正式版的新项目模板里,默认隔离和 Approachable Concurrency 的最终开启状态;以及你自己项目迁移后第一个版本的主线程性能数据。

一句话判断:Swift 6.2 拆掉的不是并发安全,而是「防御性跳线程」。如果你的项目正好要在这个窗口迁移,先改的不是代码里的注解,是脑子里那张「哪行代码跑在哪个线程」的地图——默认值变了,地图也得换。

内容由AI生成

精选参考来源

1. Swift 6.2 终于不跳线程了:150K 开发者都在聊的 Approachable Concurrency,到底改了什么?

2. Swift 6.2 之后,@MainActor 还要不要写?3 个决策点帮你理清

3. SwiftLee 深度长文:Sendable 其实是个空协议,Swift 6 并发安全一篇讲透

4. iOS 27 Beta 7推送:无新功能修复为主,正式版预计9月15日到来

5. 苹果发布iOS27系统更新!

6. 行业媒体报道,奢华定制品牌Caviar近期推出了一款名为“液态金属”的定制版折叠iPhoneUltra,整机采用925纯银打造,全球仅限量17台,起售价为18840美元(约合人民币12.7万元)。产业进展方面,国海证券表示,苹果秋季发布会预计于9月8日或9日举行,届时将推出iPhone18Pro、iPhone18ProMax以及首...全文

7. macOS27没法安装xcode26,xcode27beta编译的项目没法上架appstore。明天回退macOS26吧,幸亏用时间机器备份了数据

8. 时隔一周,苹果在今天推送了 iOS/iPadOS 27 beta 7 开发者测试版系统。不过体验半天之后,没有发现任何肉眼可见的变化。甚至存在的bug都是一模一样。

9. WWDC25:采用Swift并发|Apple

10. WWDC26:Swift的新功能|Apple

11. 这个配色好像原来的Apple intelligence的色彩啊,Xcode 27 beta ,支持Claude,Gemi

0
扫一下,分享更方便,购买更轻松
0评论

当前文章无评论,是时候发表评论了
提示信息

取消
确认
评论举报

最新文章 热门文章