从 Swift 5.5 引入符合现代编程思想的新并发模型算起,一转眼快 5 年了。从 5.5 到目前的 6.3,Swift 社区一直在采用小步迭代的方式,积极推进并发 API 的演进。但在应对过多的新关键字、复杂的隔离概念以及一些容易引发困扰的“反模式”时,这个过程对开发者来说并不算顺利。
作为一个周报编辑,我在过去几年间看到过大量的吐槽与求助,但这种焦虑感似乎从今年初开始明显转弱了。最近几个月,社区中出现了越来越多将旧项目迁移到新并发模型的成功分享。尽管其中仍夹杂着少量的抱怨,但主流态度已经展现出积极拥抱的态势。从实际的应用效果来看,经历过阵痛重构后的新代码,极大地降低了开发者在维护并发状态时的心智负担。
当然,这一现象的背后,除了开发者自身对新体系的掌握越来越熟练外,生态的成熟也功不可没。在过去的几年里,无论是第一方还是第三方框架与组件,都逐渐完成了向新并发实现的过渡。这大大降低了用户的使用门槛,让越来越多的开发者能在第一时间享受到新并发带来的便捷与数据安全。
此外还有一个有趣的因素:得益于社区众多优秀内容创作者、开源作者的无私分享,AI 在过去一两年中积累了更丰富的 Swift 并发语料。过去几个月间推出的新一代大语言模型,明显对 Swift 的并发规则有了更准确的理解,这也大大加快了开发者对新并发的掌握和应用。
在不知不觉中,Swift 新并发的发展已经进入了一个良性循环。从 Swift 6.3 的新功能就能看出,在经历了 6.2 版本之后,Swift 的并发演进已基本进入稳定期,社区的关注焦点也随之转移到了跨平台、嵌入式等更广阔的领域。
或许,Swift 的“新并发模型”这个称呼,很快就可以摘掉“新”的帽子,正式融入日常开发的血液中了。当然,也不排除再过个五到十年,又会有一个“全新”的并发模型再次惊艳(或折磨)我们。
近期推荐
一个偶发性测试失败,揭开了 Swift 并发调度的真相 (The Flaky Test That Taught Me How Swift Concurrency Actually Works)
为支持 debounce 行为编写一个测试用的 MockClock,对很多 Swift 开发者来说似乎并不复杂。但如果忽略了执行上下文(executor)的差异,结果可能就没有想象中那么确定。Xiangyu 通过一个实际案例的调试过程,揭示了 Swift 现代并发中的诸多细节:nonisolated async 函数会跳离调用者 actor;Task.yield() 只让出当前执行器;isolated 参数 + #isolation 可以让工具函数“随调用者运行”。本文的价值不在于如何实现一个测试用的 Clock,而在于它清晰地展示了 Swift Concurrency 中「任务、actor、executor、隔离」之间的真实关系。
随着 Swift 版本的发展,
nonisolated的行为也不再总是等同于“必然跳离当前调用者”,而会受到语言模式以及NonisolatedNonsendingByDefault等设置的影响。我也碰到过和本文类似的问题,同样也是通过isolated+#isolation来解决的。
「结构化并发」里的「结构化」究竟是什么意思? (What’s that “structured” in Structured Concurrency?)
尽管 Task 有句柄、可取消,比 dispatch_async 看起来“更有结构”,但在 Swift 的现代并发系统中,它的定义其实很明确:Task 是 unstructured top-level task。Max Seelemann 在本文中解释了“结构化”的真正含义:真正属于结构化并发的,其实只有两种——async let 和 TaskGroup。它们的共同点在于一种不可逃避的依赖关系:调用者必须等待子任务完成,且取消会自动向下传播。而 Task 则完全相反——可以被随意创建和遗忘,其生命周期与调用者脱钩。
文章最后给出了一条颇具实践意义的建议:能用闭包就尽量不用 Task。将工作单元表达为 () async -> Void,相比传递一个 Task 对象,更简单、更易测试,同时取消行为也会自然继承自调用上下文。
.refreshable 自己终结自己的陷阱 (SwiftUI: Refreshable Task Cancellation)
.refreshable 接受一个异步闭包,开发者可以在其中获取新数据并更新视图状态。但它有一个容易踩到的陷阱:如果在闭包执行过程中修改了驱动当前视图的 @State,由此触发的视图重绘,可能会让 refreshable 的任务在完成前被取消。Anton Gubarenko 在本文中对这一行为做了清晰解释:.refreshable 的任务生命周期与视图绑定,当刷新过程中触发重绘时,SwiftUI 可能提前终止该任务,也就是“任务被自己触发的更新所取消”。
作者给出了两种修复思路:要么将中间结果收集到本地变量,最后一次性更新状态,避免多次触发重绘;要么将实际工作包裹在 Task { }.value 中,使其从当前刷新任务中“脱离”,从而避免被视图生命周期打断。
.refreshable面临的问题,在.task中同样存在。这并不是 Bug,而是 SwiftUI 对结构化并发的一种具体体现:异步任务依附于视图生命周期,并随其结束而被取消。如果没有意识到这一点,就很容易在状态更新与任务执行之间制造出“自我取消”的场景。
Swift 6.3 experimentalCGen 指南:SwiftPM 原生支持 C 代码生成
Swift 6.3 引入的 experimentalCGen 填补了 SwiftPM 长期以来的一个关键缺口:Build Tool Plugin 生成的 C-family 产物,终于可以直接参与 C module target 的编译,而不再依赖外部脚本或预提交的生成文件。这意味着完整的构建图可以在 SwiftPM 内闭环——本地、CI、Xcode 使用同一套规则,不再各自维护一部分构建知识。Snow 在本文中详细梳理了其背景、用法与迁移思路。
experimentalCGen目前仍有明确限制,例如同一 target 只能有一个生成的 module map,且 module map 引用的 header 需要位于同一目录。因此它更适合边界清晰、输出稳定的代码生成场景,而不是用来替代完整的原生构建系统。
将 300 个视图迁移到 SwiftUI 后所学到的 (How I migrated 300 screens to SwiftUI and what I learned)
将 300 个界面迁移到 SwiftUI,听起来像一次彻底的转型,但 Artem Mirzabekian 及其团队的策略却相当克制:SwiftUI 只负责 UI 构建,导航依然留在 UIKit。这种分层并非妥协,而是有意为之——让团队在享受 SwiftUI 布局与组件复用优势的同时,避免在导航、深链路和复杂流程上引入不必要的风险。文章记录了迁移中反复出现的问题:团队习惯了命令式思维,常把 SwiftUI 当作“语法不同的 UIKit”来写;body 中夹带副作用、将 onAppear 当作 viewDidLoad 使用、嵌套 ObservableObject 导致状态传播不如预期……这些问题在迁移过程中一再出现。经过持续的审查与内部工作坊,团队最终沉淀出一套清晰的架构方向:MVVM + 枚举驱动的状态与交互建模 + Use Case 分离业务逻辑。
即便不是迁移项目,SwiftUI 与 UIKit 混用也是一种现实且有效的选择。两个框架并非对立,混用本身不难,难的是在各自的思维模型下写出符合其设计意图的代码。
工具
Mini Swift: 纯 C 写的 Swift 编译器
一个很有趣且极具极客精神的项目。Ugur Toprakdeviren 在不使用 LLVM、Clang 或苹果任何官方工具链的情况下,单枪匹马用 7 万多行 C 语言“手搓”了一个轻量级的 Swift 编译器。他从词法分析、抽象语法树一路写到了直接输出 WASM 的后端,为网页端带来了 0.1 毫秒级“秒编译”的惊人体验。在这个动辄拉入几百兆依赖包的时代,这种零依赖的“徒手造轮子”行为无疑是一种复古的浪漫。
这个项目源于作者一个简单初衷:做一个不会崩溃的 SwiftUI 浏览器预览。作者透露,他目前正在开发一个名为 UIIR(UI 中间表示)的层,最终目的是想把 SwiftUI 代码映射成一套平台无关的指令,直接在 Web 甚至 Android 上渲染出原生效果,以此来完成他最初的设想。
该编译器前端的核心代码(词法、语法、语义分析)目前已 开源。
如果结合终端版本的 WASM 运行时(如 Wasmtime 等),或许 Mini Swift 可以大幅改善目前 Swift 编写终端脚本时冷启动过慢的痛点,真正提升 Swift 的脚本化体验。我很期待社区在这个方向上的尝试。
Yotei: SwiftUI 日历组件库
Yotei 是一个 iOS 日历组件库,作者是 Mikalai Zmachynski。项目提供了 SwiftUI API,同时在日程列表、分页和时间轴等高负载场景中借助 UIKit 保持滚动性能。它有 date picker、day timeline、month grid、schedule list 等组件,也给了较细的定制入口。
Yotei 展示了一种在复杂 SwiftUI 组件中越来越常见的取舍:SwiftUI 负责组合、状态绑定与扩展点,UIKit 负责更成熟、稳定的列表和分页体验。
Runtime Viewer
如果你还记得 RuntimeBrowser,那么 Mx-Iris 开发的 Runtime Viewer 可以看作它在今天苹果平台语境下的一次现代化重写。它不仅能浏览 Objective-C runtime 信息,也把 Swift 类型、枚举布局、VTable 偏移等内容纳入了分析范围,并提供接近 Xcode 的代码阅读体验。
它不只是“能看更多接口”,而是把运行时检查、跨进程通信、代码注入、Bonjour 设备发现,甚至 MCP 接入放进了同一个工具里。对逆向、安全研究、系统 Framework 学习,或者只是想理解某个二进制内部结构的开发者来说,它都更像一个面向现代 Apple 平台的 runtime inspection 工作台。