iPhone Duo 带来的机遇与挑战 -- 肘子的 Swift 周报 #153
iPhone Duo 带来的机遇与挑战尽管 iPhone Duo 的设计资料早在几个月前就已部分泄漏而且苹果也是折叠机领域的后来者但凭借软硬件整合能力它所带来的交互变化还是给不少消费者带来了惊喜。不同机构对 iPhone Duo 的初期销量给出了不同口径的预测Counterpoint 预计其 2026 年内出货量最高约 600 万部IDC 则预计上市后前 12 个月可能达到约 1000 万部。在整个 iPhone 销量中这仍然只占一小部分但与 Vision Pro 上市两年半的几十万销量相比这个数量已经足以支撑不少特别针对这款设备开发的应用了。这几天我已经在社交媒体上看到不少针对 Duo 形态的创意相信一旦其中出现几个爆款也会进一步推动设备的销量。尤其是Duo 相比 Vision Pro 具备更强的社交展示性特别的硬件、特别的应用所带来的“特别感”正是不少首批购买这类产品的用户所追求的。但对于更多开发者来说iPhone Duo 独特形态带来的适配压力也是真实的。Duo 包括内外两块屏幕内屏又可以以展开、半折叠等多种姿态存在可以说是 iPhone 家族中适配难度最高的产品之一。苹果确实提供了不少有针对性的适配 API标准容器在各种姿态下也已基本自适应但这些只解决了 UI 层面的问题。真正难的是 UXAPI 能告诉你可用空间有多大、铰链落在哪里却无法告诉你半折叠时用户究竟想看到什么。多一种姿态就多一次需要重新设计的体验。对于使用 Flutter、React Native 等第三方框架的团队问题还要更靠前一步不是适配得好不好而是拿不拿得到信息。Flutter 的MediaQuery.displayFeatures在 Duo 上无论折叠到什么角度都返回空列表React Native 则至今没有任何与折叠状态相关的官方 API。当硬件本身开始成为交互的一部分跨平台框架就必须在屏蔽平台差异与暴露平台能力之间做出更多取舍而这种取舍很难由框架单方面消化——它总是滞后于平台。事实上在 Duo 发布之前重新评估跨平台方案的趋势就已经出现其背后是一组正在同时发生的变化AI Coding Agent 大幅降低了原生开发与维护的成本而 Liquid Glass、Duo 这样的变化又在不断抬高用足平台特性的价值。跨平台方案的性价比正被这两头同时挤压。Notion 正在将基于 Web 技术栈的苹果端 UI 迁移到 SwiftUIShopify 则在几乎同一时间宣布将移动端从 React Native 迁回 Swift 与 Kotlin理由之一是编码模型的进步正在削弱“避免把同一个功能造两遍”这一跨平台开发的重要成本优势。与之一并发生的是它对旗下 React Native 开源库的交接。对于苹果生态来说iPhone Duo 是一个真正带来变化的产品。过去几年苹果平台的变化更多发生在软件和设计语言上而 Duo 则重新改变了开发者面对的硬件形态。它的生态意义或许并不在于多卖出几百万台设备而在于当设备本身再次成为应用设计的一部分时“使用平台原生框架”这件事正在从一道偏好题变成一道成本题。本期内容 | 前一期内容 | 全部周报列表近期推荐调试卡顿的根源Swift 如何追踪 Module (Module Tracking in Swift Debug Info)你是否碰到过这样的情况一个看似简单的 LLDB 表达式在断点调试时却迟迟没有反馈为了计算属性、调用方法等操作LLDB 有时需要启动 Swift 编译器并寻找和加载相关 Module。过去这套过程并不总能准确找到构建时实际使用的 Module甚至可能重新编译部分依赖让一个原本简单的调试操作变成长时间等待。Adrian Prantl 介绍了一个从 Swift 6.3 开始引入、并在 6.4 中进一步完善的机制Module Tracking。新的机制让调试信息能够更明确地告诉 LLDB“构建时用的就是这些 Module它们就在这里”从而减少不必要的寻找和重新编译。Swift 6.4 还会改善 bridging header 的处理并让调试产物明显瘦身——Darwin 上的 dSYM 不再打包二进制 Swift ModuleWindows 与 Linux 上带调试信息的二进制同样受益。Swift 6.4 中补齐的几处 Hashable (New Hashable conformances in Swift 6.4)Artem Mirzabekian 介绍了 Swift 6.4 中几个新增Hashable支持的标准库类型它们分别来自 SE-0514Dictionary.Keys、CollectionOfOne、EmptyCollection和 SE-0523UnownedTaskExecutor。其中最贴近日常开发的是Dictionary.Keys现在可以直接放入Set或作为 Dictionary 的 key而不必先转换成其他类型。值得留意它的语义两个Dictionary.Keys只要包含相同的键就视为相等顺序不参与比较与哈希——这与字典本身的身份认定是一致的。Dictionary.Values没有一并获得该能力因为值可以重复需要的是 Swift 目前没有的多重集合语义。虽然只是一次小幅补全但也让这些类型在泛型和集合场景中的使用更加自然。Vein 中的惰值性能 (How to list big models cheaply: Vein vs SwiftData)两周前我在 SwiftData优化从建模开始 中讨论了“胖模型”给 SwiftData 列表带来的内存和性能压力并尝试通过模型拆分减少一次查询真正加载的数据。Mia Köring 使用了我文章中的测试代码展示了她开发的 Vein 持久化框架在字段级惰性加载下的表现。Vein 采用了与 SwiftData Model 类似的声明方式默认同样是属性预加载、关系惰性加载不同之处在于给某个属性标注LazyField后它会推迟到真正被访问时才去读取。因此在“只显示标题”的列表场景中无需拆分模型也能取得不错的成绩。让自动化自己证明它做对了 (Sad But True: Localized App Store Screenshots That Verify Themselves)自动化被越来越多地应用到 App 开发的各个环节但有时实践中的难点并非如何实现自动化而是如何让它自己证明“我做对了”。Wesley Matlock 在通过自动化方式为 App Store 生成多语言截图时发现西班牙语截图悄悄回退成了英文而整个测试流程依然通过。检查后发现原因来自 Xcode 27 下-testLanguage没有可靠地应用到 App。Wesley 随后改用simctl设置 Simulator 的语言并通过比较截图的 SHA-256自动检查不同语言或不同页面是否意外生成了完全相同的图片。Wesley 基于截图哈希的比较思路可以迁移到任何“把请求交给黑盒、再把产出照单全收”的流程里。Transition or ContentTransitiontransition和contentTransition名字很像但解决的是两类不同的问题前者用于 View 被插入或移出视图层级时的动画后者则用于 View 仍然存在、只是显示内容发生变化的情况。Stewart Lynch 通过条件视图、数字变化和 SF Symbols 等例子对两者进行了直观比较并介绍了.numericText、.interpolate、.symbolEffect等常用的内容过渡效果。在 SwiftUI 中transition很早就支持自定义但这种能力始终没有延伸到 Sheet、导航切换等更高层级的场景。这些场景与contentTransition类似目前仍主要依赖系统提供的有限几种过渡方式。期待未来 SwiftUI 能进一步打通这些不同层级的 transition 概念或者至少为开发者提供更多自定义空间。用 Scope 为视图状态划一条边界 (Abstracting SwiftUI state with scopes)在 SwiftUI 中如果视图中有多个State我们可能会将它们抽象到一个Observable中。但如果视图还依赖其他环境值或其他Observable实例呢是否有一种方式可以将来自不同数据源的状态组织到一起同时减少视图对具体数据源的耦合Mike Apurin 提出了 Scope 思路通过他开发的 ScopedState 将多个状态源组织到统一的访问边界中只向 View 暴露当前界面真正需要的状态和操作。View 无需了解这些状态实际来自哪里也更容易在 Preview 和测试中替换数据来源。需要注意的是这并不是试图创建另一套类似 TCA 或 MVVM 的状态管理模型而是一种作用于 View 层级、对现有状态源进行组织和抽象的方式。折叠之前iPhone Duo 适配iPhone Duo 的推出让消费者在惊叹设备形态变化的同时也给开发者带来了新的挑战如何利用更大的显示空间如何让现有布局适应不同的设备形态以及如何利用折叠、多显示区域等新的交互能力。上周不少内容创作者都从不同角度给出了自己的建议。苹果在发布当天放出了六个 Tech TalkDesign for iPhone Duo、Prepare your app、Raise the bar、Strike a pose with adaptive layouts、Leverage multiple displays and scenes、Build a great camera experience并在 HIG 中增加了 Designing for iPhone Duo 一页。Florian Schweizer 强调“不要与框架对抗”不要从判断“是不是 iPhone Duo”开始而应该问“这个视图拿到了多少空”。他还将这些原则以及 Duo 的新 API、Apple 开发者资料整理成了一个 SwiftUI iPhone Duo Skill供 Coding Agent 在适配现有 App 时使用。Lee young-jun 从现有 App 的实际适配出发通过NavigationSplitView、sidebarAdaptable、Device Hub 的 Resizing Mode 等方式提前检查和改善 App 在 iPhone Duo 不同显示形态下的表现。Sagar Unagar 根据 Apple 最新的 HIG 和开发者资料梳理了 iPhone Duo 在自适应布局、系统控件、折叠区域以及不同显示形态下的主要设计原则。Jordan Morgan 总结了开发者首先需要关注的布局、系统栏、safe area、相机以及多显示区域等变化。Artem Mirzabekian 介绍了新的ArrangementView开发者可以描述两组相关内容之间的关系让 SwiftUI 根据可用空间和折叠区域自动选择合适的布局方式。上面介绍的功能不少都只存在于 Xcode 27.1 中想完整体验还需要一段时间。工具SwiftMusic用 Swift 声明音乐Norikazu Muramoto 开发的 SwiftMusic 是一套面向 Apple 平台开发者的声明式音乐创作框架。它借鉴了 SwiftUI 的设计理念将Music、Sound、body、Result Builder 和 Modifier 等熟悉的 Swift 表达方式带入音乐创作让节奏、旋律、和声、音色、效果器和混音关系都可以通过组合代码来描述。例如鼓点、贝斯和合成器可以直接写成具有音乐含义的 Swift 代码struct Session: Music { var body: some Sound { Track(Drums) { Sample(kick) .rhythm(x ~ x ~) } Track(Bass) { Synthesizer(.saw) .notes(C2 ~ Eb2 G2) .gain(0.3) } } }SwiftMusic 本身并不发声它只把声明编译成节拍域事件与渲染计划既不打开音频设备也不绘制编辑器实际的音频渲染由宿主负责——作者另外提供了 macOS 端的实时编辑器 MusicPlaygournd 来承担这部分工作。Homebrew 7一次告别 Intel 的大版本Homebrew 7.0.0 正式发布除了多项功能和内部实现调整本次大版本也带来了值得关注的兼容性变化。目前 Apple Silicon Mac 上的 macOS 15–27 属于完整支持范围而 Intel Mac 已全部降为 Tier 3不再获得完整 CI 支持和新的 bottles并计划在 2027 年 9 月或之后彻底停止支持。仍在 Intel Mac 或较旧 macOS 上使用 Homebrew 的开发者需要特别留意。往期内容当 Mac mini 的价格不再 mini - #152热茶还是冰咖啡 - #151AI 想放弃了人没有 - #150越来越慢的 App Review拦住了谁 - #149 支持与反馈如果本期周报对你有帮助请点赞- 让更多开发者看到评论- 分享你的看法或问题转发- 帮助同行共同成长拓展 Swift 视野 邮件订阅| weekly.fatbobman.com 获取独家技术洞察 开发者社区| Discord 实时交流开发经验 原创教程| fatbobman.com 学习 Swift/SwiftUI 最佳实践