Issue #142

SPI 加入 Apple,Swift 迈向自举

Cover for Weekly Issue 142

Photo by Alan Aprilio on Unsplash

几天前,Swift Package Index(SPI)宣布已加入 Apple。双方将共同建设一个面向 Swift 开发者的综合 package registry;与此同时,SPI 现有的包发现、兼容性检查、文档托管等能力仍会继续提供,包作者在短期内也无需调整现有的发布流程。

这也让 #135⁠ 中“SwiftPM 才刚到第二章”的判断得到了新的注脚:CocoaPods 的退场只是把 SPM 推上了默认位置,而 SPI 加入 Apple,才真正揭开了 Swift 包生态基础设施建设的下一幕。

如果说 SwiftPM 解决的是“能不能方便地依赖包”,SPI 解决的是“能不能找到并评估包”,那么这次加入 Apple 则把问题进一步推进到了“能不能可信地发布、识别和分发包”。从中期来看,有三点尤其值得观察:

  • SPI 将从第三方索引服务,演进为官方 package registry 的重要入口;
  • Swift 包生态可能逐步降低对 GitHub 作为托管、分发与身份来源的隐性依赖;
  • Xcode 有机会与 SPI 的搜索、兼容性检查和文档能力建立更紧密的集成。

上周,另一件让 Swift 开发者振奋的事情是,Erik Eckstein 在 Swift 论坛上宣布,Swift 项目将取消“必须能够仅使用 C++ 宿主工具链构建编译器”的要求。换句话说,从 main 分支开始,构建 Swift 编译器将需要已有的 Swift 工具链参与;这也使得编译器中那些过去必须保持 C++ 实现的强制路径,现在可以逐步用 Swift 编写。官方提到的范围包括 Parser、AST、Type Checker,以及 mandatory SIL passes 等核心部分。

这并不意味着 Swift 编译器已经完全用 Swift 重写,也不意味着 C++ parser 会马上消失。更准确地说,这是 Swift 编译器迈向自举和自托管的重要门槛:Swift 不再只是用于外围工具、可选功能或个别优化 pass,而是可以进入编译器的核心路径。

自举本身并不能简单证明一门语言能力的高低,但它代表了一种工程成熟度:语言、编译器、标准库、包管理器和跨平台构建系统,是否已经强大到足以支撑自身的持续演进。对于一个希望在 Apple 平台之外继续扩展影响力的语言来说,这一步的象征意义和实际价值都不小。

把 SPI 加入 Apple 与 Swift 编译器迈向自托管放在一起看,会发现它们指向的是同一件事:Swift 正在补齐生态基础设施。前者关乎包的发现、身份、签名和可信分发,后者则提升了语言工具链自身的可维护性与演进能力。Swift 能否真正破圈,关键并不只在于 Apple 在其中拥有多大的影响力,而在于 Apple 与 Swift 社区是否能持续展现开放、进取的态度,并把工具链、包生态和跨平台体验打磨到足够完整。就这两件事而言,我愿意保持乐观。

近期推荐

在 Apple II 上跑 Swift (Bring Swift to The APPLE II)

Apple II 是苹果早期最重要的产品之一,至今仍影响着许多开发者。很多人都曾在它上面使用 BASIC 或 Apple Pascal,但如果在这台机器上写 Swift,又会是什么体验?Yeo Kheng Meng⁠ 实现了一个 Swift 风格的迷你开发环境 SwiftII,让一台搭载 1 MHz 6502 CPU、64 KB 级别内存的老机器也能编写和运行类似 Swift 的程序。

文章精彩的地方不只是“让 Apple II 跑上类 Swift 语言”,还包括大量围绕硬件限制的工程取舍:有限的内存空间、语言卡和 ProDOS 的冲突、不同 Apple II 机型的键盘与显示差异,以及为什么最终要拆成多张磁盘镜像发布。作者也坦诚分享了 AI 辅助开发的过程。即便有 Claude Code 和 Codex 的帮助,关键的架构取舍、范围控制和硬件测试策略仍然需要作者自己把关。本文既有复古计算机的工程细节,也有现代语言设计在极小环境中的取舍。


基于 WebAssembly 实现 Swift App 热更新 (Building an over-the-air update system for native Swift with WebAssembly, from scratch)

为原生 Swift iOS App 构建 OTA 更新机制,是一个有争议但也很有价值的方向。Jack Solomon⁠ 在这篇文章中展示了基于 WebAssembly 的实现思路:将 Swift 函数编译成 WASM,再通过 WasmKit 在 iOS App 内加载执行,随后从服务器下载新的 WASM 模块,让 App 在不重新构建、不替换已签名二进制的情况下改变运行结果。

文章拆解了 Swift to WASM 的工具链、WASI、@_cdecl 导出、reactor module、线性内存传参,以及 SwiftUI 视图热更新为什么需要 dynamic replacement 和可序列化的视图描述树。Jack 也将这套思路包装成了 Swift SDK:patch-swift⁠。

需要注意的是,这类方案触及 App Store 审核规则中关于下载和执行代码的边界,实际使用时仍需要谨慎评估场景和合规风险。


理解 SwiftUI 的底层核心:属性图 (SwiftUI Is One Graph)

Mihaela Mihaljević Jakić 在过去一周连续发表了两篇关于 SwiftUI 底层机制的长文,值得放在一起阅读。第一篇 SwiftUI Is One Graph 从实际行为和 Apple 专利出发,解释 SwiftUI 并不是简单的 View Tree diff,而更像是一个 demand-driven attribute graph:View struct 本身只是可丢弃的描述,真正持续存在的是属性图,以及其中的状态、依赖、布局和动画传播。

第二篇 《The SwiftUI Oracle: Measuring a Clean Room Against the Real Thing》则进一步展示了如何验证这种理解。作者实现了一个不依赖 SwiftUI 的 clean-room 引擎 PureView,再把真实 SwiftUI 当作 oracle,通过布局、动画、像素渲染等 differential testing 去验证自己的模型。

Mihaela 的工作流对 AI agent 很有启发。Agent 不需要只靠语言模型去猜 SwiftUI 行为是否正确,而是可以生成或修改实现,然后运行测试,让真实 SwiftUI 给出可比较的结果。这种类似“单元测试”的反馈闭环,能把对黑盒框架的理解变成可以持续验证和迭代的工程信号。


在 SwiftUI 中实现可拦截回调的菜单与选择器 (SwiftUI: Intercept-able Picker / Menu / Context Menu)

很多场景下,开发者都希望能在 MenuPickercontextMenu 等组件弹出前执行一些同步操作,比如统计打开次数、更新状态,或者临时决定是否允许展示。但 SwiftUI 并没有提供对应的回调。Itsuki⁠ 在这篇文章中分享了自己的实现思路:通过桥接一个承载 SwiftUI 内容的原生 View,在对应手势触发时先执行 menuWillOpen,再决定是否使用 NSMenu.popUpContextMenu 等 AppKit API 主动展示菜单。

本文再次体现了 SwiftUI 的一个现实问题:很多看似简单的交互控制,一旦超出系统 modifier 暴露的能力,仍然需要理解底层 AppKit / UIKit 才能真正解决。


解析 UIPortalView:从视图实时投影到流体玻璃特效 (_UIPortalView: From Live Mirroring to Liquid Glass-Style Effects)

Artem Mirzabekian⁠ 分享了 UIKit 中一个有趣的私有组件 _UIPortalView。它由 CAPortalLayer 支持,可以把某个 sourceView 的渲染结果实时投射到屏幕上的另一个位置,而不需要复制一份 View 层级,也不需要反复生成 snapshot。相比静态快照,Portal 更像是合成层上的“实时窗口”:源视图仍然是唯一状态来源,而文本、动画、布局或子视图变化都可以同步反映到另一处显示。

文章还把 _UIPortalView 和 Liquid Glass 效果联系起来:通过 matchesPosition、裁剪、偏移和 3D transform,可以实现实时镜像、反射、镜头、共享背景和边缘扭曲等效果。


掌控 SwiftUI 工具栏新 API (Taking control of toolbar items in SwiftUI)

WWDC 26 带来的新 SwiftUI Toolbar API,让系统自适应和开发者显式控制之间取得了更好的平衡。Majid Jabrayilov 在这篇文章中介绍了几项新的控制能力:通过 visibilityPriority 指定 toolbar item 的显示优先级,用 ToolbarOverflowMenu 明确创建折叠菜单,借助 .topBarPinnedTrailing 将重要操作固定在顶部栏尾部,以及使用 toolbarMinimizeBehavior 控制导航栏、标签栏、底部栏等在滚动时的最小化行为。

同一组 toolbar items 在 iOS、iPadOS 和 macOS 上可能会有不同的展示方式。新 API 的价值在于,它们没有破坏 SwiftUI Toolbar 原本的跨平台自适应能力,却让开发者可以更明确地表达哪些操作应该优先显示、哪些操作可以主动放进 overflow,以及工具栏应该如何响应滚动。

工具

iOS-Simulator-Camera-Extend:给 iOS Simulator 补上“真实可用的相机”

iOS Simulator 一直没有真正的相机能力,涉及扫码、OCR、人脸、视频通话、AVCaptureSession 的功能,往往只能上真机或写模拟逻辑。由 Shuyu Guo⁠ 开发的 iOS-Simulator-Camera-Extend 复刻了 SimCam 的核心思路,通过 macOS 端帧源、Simulator 内 DYLD_INSERT_LIBRARIES hook 与 AVFoundation swizzle,让被测 App 无需改代码、无需换 bundle id,就能在模拟器里拿到 Mac 摄像头、桌面、图片、视频和二维码画面。

更有意思的是,它还提供了另一条 CMIO System Extension 链路,让 QuickTime、FaceTime、Zoom、OBS 等 macOS 应用也能看到一台 SimCam Virtual Camera。也就是说,同一份帧源既可以喂给 iOS Simulator 里的 App,也可以作为 macOS 虚拟摄像头使用,对相机相关功能的调试、演示和自动化测试都很实用。

相关周报

订阅 Fatbobman 周报

每周精选 Swift 与 SwiftUI 开发技巧,加入众多开发者的行列。

立即订阅