当前位置:
AIGC文章详情

iOS 27 正式版倒计时1个月:Swift 6 迁移成本被三个版本打下来了,老项目迁不迁先算这笔账

源自14位全网作者

07:39

iOS 27 Beta 6 已经在 8 月中旬推送,苹果把测试节奏从两周一更调成了每周一更,意味着 iOS 27 开发正式进入收尾打磨阶段。知乎按照惯例,iOS 27 正式版将在下个月跟着 iPhone 18 一起发布。知乎而从 Beta 6 开始,苹果已经不再新增功能或进行改动,全力修复已有问题。36氪

iOS 27 正式版倒计时1个月:Swift 6 迁移成本被三个版本打下来了,老项目迁不迁先算这笔账

对做 iOS 开发的人来说,随系统一起到来的还有秋天的 Xcode 27。装上新 IDE 之前,那个被拖了两年的问题又会浮上来:手里的 Swift 5 老项目,到底要不要迁到 Swift 6 严格并发?今年和去年不一样了,这笔账值得重新算一遍。

先说清楚大家为什么怕迁

拖延的理由都摆在明面上。知乎上有个标题很扎眼的帖子,《为什么Swift大型软件开发是一托构式》,90 多个赞、40 多条评论,点赞最集中的吐槽有两条:有的第三方包为了很少用的功能放弃 Swift 5 兼容,中等项目从 Swift 5 迁到 Swift 6 会多出几百个编译错误,包生态被分裂。知乎错误越改越多、改完一批又冒出一批,是很多人对迁移的全部印象。

这个帖子还有一句话,其实从反面解释了为什么该迁:Swift 5 时代对竞态的检查并不严格,data race 大概率只抛运行时警告,小概率直接崩溃,数据流复杂的异步项目开发期找不出问题,上线才猛出问题。知乎这类偶发并发崩溃,恰好是线上最难排查、最耗人力的一类问题。

三个版本连着把门槛往下打

如果对 Swift 6 的印象还停在"报错洪水",那信息确实过时了。从去年秋天到现在,6.2、6.3、6.4 三个版本的方向出奇一致:不加新范式,专门拆迁移路上的石头。

Swift 6.2 最核心的一刀砍在线程模型上。以前 nonisolated 的 async 函数,一被 await 就被丢到全局线程池,想更新 UI 还得手动跳回来,调用链越深越像迷宫;开启 Approachable Concurrency 之后,默认行为翻转,nonisolated async 不再跳全局线程池,而是留在调用者所在的执行上下文上执行,想真去后台就显式标 @concurrent。知乎迁移时最常见的"为什么我的代码乱跳线程"这一大类错误,直接从源头变少了。同一代里,Xcode 新建项目还默认开启了主 actor 隔离,app target 里的代码默认都跑在主线程,除非显式退出隔离。知乎写新代码的思路从"什么时候加 @MainActor"变成了"什么时候用 nonisolated 退出去"。

今年 3 月的 Swift 6.3 是第一个把 Android SDK 纳入官方发布版本的 Swift 版本,语言生态的盘子在变大。知乎对迁移本身,它补了一个不起眼但好用的小特性:weak 可以配 let 了。写过 delegate 的都懂,weak var delegate 在 Sendable 类里过不了检查,以前只能绕,现在改一个词就能过。weak 引用以前必须是 var,而 var 属性在 Sendable 类里是不被允许的。知乎

iOS 27 正式版倒计时1个月:Swift 6 迁移成本被三个版本打下来了,老项目迁不迁先算这笔账

6 月 WWDC 发布的 Swift 6.4,则是给严格并发做的一次集中打磨:defer 里可以直接写 await,事务回滚这类异步清理不用再在多个出口重复;取消保护让必须做完的收尾工作暂时屏蔽取消信号;以前会被静默吞掉的 throwing Task 错误,现在编译期就有警告;~Sendable 让库作者显式标注"这个类型不能跨线程",下游不用再猜。用 SwiftLee 的总结说,没有一个特性引入全新编程范式,都是对严格并发模式的打磨,让开发者在遵守规则时少踩坑。知乎

这笔账:买到什么,付出什么

先说买到的是什么:把过去只能等上线才暴露的并发 bug,挪到编译期拦住。有个真实坑很能说明问题——在 Swift 5 模式下,从后台线程同步调用一个标了 @MainActor 的方法,它会就地跑在后台线程上,编译器一声不吭;有团队排查 UI 偶发崩溃,最后发现就是这个调用方式把 UI 更新扔到了后台线程。知乎同样的代码在 Swift 6 模式下编译就直接报错。偶发崩溃的排查成本,远高于一次迁移的投入。

再说付出的是什么。第一是处理错误的工作量:SwiftLee 拿自己的项目试,大约 17 个警告。知乎小项目这个量级,大项目就是前面说的几百个起步,社区有个参考案例:一个 50 万行的中型项目从 Swift 5 迁到 6.2 默认隔离,大约花了 2 到 3 周。知乎这只是个例,但量级可以参考:迁移不是半个下午的事,得按迭代排期。第二是第三方依赖风险:Sendable 合规声明必须写在类型定义的源文件里,依赖的库不合规,你改不了它,只能 @preconcurrency import 暂时静音警告。第三是认知切换:nonisolated、@concurrent、sending 的语义都变了,团队要一起对齐一遍。

三种项目,三个答案

新项目没什么可犹豫的。新 Xcode 建出来的项目默认就在新隔离模型下,新代码按新写法走,零历史包袱,现在恰好是学习成本最低的窗口。

老项目看状况。工程大、协作人多、出过并发类线上事故的,值得迁,但别一步到位:先把 SWIFT_STRICT_CONCURRENCY 开到 targeted,只完整检查用了 async/await 的代码,先暴露真问题、不被存量代码淹没;清完再开 complete,最后切 Swift 6 语言模式。项目小、并发场景少、从没崩过的,可以缓,但建议先把 targeted 打开看一眼警告数量,给自己留个决策依据。SwiftLee 有个很实在的建议:如果项目还没开始迁移,可以等升到 6.2 以上再动手,体验会好不少。知乎

做 SDK 和库的,建议尽早迁。你的类型是不是 Sendable,直接决定下游用户的报错数量;真不能跨线程的类型,用 ~Sendable 把意图标明白,比让别人猜你是忘了加还是故意不加强得多。

什么时候动手,后面盯什么

时间上,iOS 27 正式版 9 月落地,Xcode 27 稳定版随后就到,团队年内换环境基本是定局。现实点的安排是:等 Xcode 27 正式版发布后再启动迁移,用下一个提审窗口前的版本缓冲期做完,别和大版本功能开发挤在一起。

动手之后,处理最多的 Sendable 报错有个现成的优先级:能改值类型就改,struct 加 let 隐式合规、零成本;需要引用语义就用 actor 或 @MainActor 隔离;类内部需要可变状态,用 Synchronization 框架的 Mutex 包起来,编译器全程可验证;实在不行才用 @unchecked,那等于告诉编译器别查了,未来有人加了不加锁的属性,数据竞争会悄悄回来。闭包跨隔离域传递时加 @Sendable,编译器检查的就是闭包捕获的值是否安全——闭包捕获外部状态这件事,在严格并发下从语言特性变成了要过审的对象。

iOS 27 正式版倒计时1个月:Swift 6 迁移成本被三个版本打下来了,老项目迁不迁先算这笔账

往后值得盯三个信号:Xcode 27 正式版里 Swift 6.4 的实际落地表现;常用第三方库补 Sendable 支持的速度——代码里的 @preconcurrency 只是把警告静音,不是解决问题,库更新之后要记得删掉。知乎以及苹果下一个提审窗口对构建工具的要求。这笔账算到这里,答案已经不是迁不迁,而是排进哪个版本、哪个迭代。

内容由AI生成
0
扫一下,分享更方便,购买更轻松
0评论

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

取消
确认
评论举报

最新文章 热门文章