
在 weekly.fatbobman.com[1]订阅本周报的电子邮件版本。访问我的博客 肘子的 Swift 记事本[2]查看更多的文章。加入 Discord[3]社区,与 2000+ 中文开发者深入交流 Swift、SwiftUI 开发体验。

父亲的 iPhone 16 突然无法充电。预约后,我前往 Apple Store 送修。工作人员确认问题后,为我提供了一部 iPhone 14 作为备用机,并协助完成数据转移。十二天后(期间正好赶上一个长假),设备维修完成——更换了 Type-C 接口,同时还免费更换了一块新电池。体验一如既往地令人满意。
这些年来,我修过不少苹果设备。印象较深的几次包括:因“显卡门”事件,MacBook Pro 免费更换主板;2011 款 iMac 27 英寸因屏幕进灰,免费更换显示屏。其他一些小问题,如果时机合适,有时会直接换新设备。
网络上确实不乏关于 Apple Store 或授权维修商的不愉快经历。但就我个人而言,多次维修体验都算顺利——或许得益于对设备问题的充分了解,以及始终保持友好的沟通态度。
一个有趣的观察是:Apple Store 里有相当多的老年用户。与天才吧工作人员闲聊时得知,许多年轻人会把淘汰的 iPhone 或 iPad 送给长辈,或直接购买新设备作为礼物,但往往没有时间教他们使用。于是,天才吧相当一部分工作量,变成了帮助老年人注册账户、安装应用、指导基本操作。
天才吧的存在,让全年龄段用户都能享受科技的便利——既服务了消费者,也增强了品牌的用户粘性。如今许多其他品牌也开设了规模不小的线下门店,但大多仍停留在展示与销售层面。在网购已成主流的时代,实体店的价值早已超越“卖产品”,更在于那种人与人面对面交流的温度——这,正是 Apple Store 的重要魅力所在。
欢迎 点赞 ♥️、 转发 👉
虽然 Xcode Preview 为开发者带来了极大便利,可以即时查看 UI 的变化,但它仍存在不少限制。Daniel Hooper[5]在本文中展示了一种巧妙的热重载方案:将 UI 与应用逻辑编译为动态库(dynamic library),并由宿主 App 在运行时加载。当代码变更时,重新加载新库并替换旧库。这一方案的亮点在于:支持完整应用运行、可保留状态,不依赖 Xcode。整个实现仅需约 120 行代码,充分体现了“理解原理后,复杂功能也能以简洁方式实现”的魅力。
尽管 SwiftUI 的列表能力持续进步,但在大数据量、复杂交互或需要精细控制的场景中,UITableView 依然不可替代。相较于 SwiftUI 的声明式简洁,UITableView 的数据源管理更易出错,批量更新也常因数据与 UI 不一致而崩溃。Kingnight (Jinkai)[7]通过一个功能完备的音乐播放列表示例,系统讲解了 UITableViewDiffableDataSource 的现代用法。
文章不仅覆盖基础,还深入对比 reconfigureItems与 reloadItems的性能取舍,拆解拖拽重排与滑动删除的实现,并通过 BaseReorderableDiffableDataSource 与 DiffableTableAdapter 给出可复用的架构实践。无论是在 SwiftUI 项目中集成 UIKit 列表,还是维护现有 UIKit 项目,这都是一份扎实的现代化指南。
iPhone 17 系列的屏幕配置迎来重大调整:Plus 型号被取消,取而代之的是全新的 iPhone Air(6.5 英寸)。基础版 iPhone 17 与 Pro 版共享同一块 6.3 英寸显示屏,这也意味着基础款首次获得 ProMotion 与 Always-On Display 等 Pro 级特性。值得注意的是,所有新机型在横屏模式下新增了 20 pt 的顶部安全区内边距。
Keith Harrison[9]整理了所有 iPhone(及 iPod touch)自 iOS 15 起的完整屏幕尺寸与安全区(Safe Area Insets),并更新了 App Store 截图要求:开发者可继续使用 6.9 英寸(1320 × 2868)或 6.5 英寸(1242 × 2688)规格上传主截图。
移动应用无法“热修复”,一旦上线崩溃,就要经历审核与分阶段发布,因此预防远比补救重要。Tjeerd in ’t Veen[11]通过“组合爆炸”问题深入分析了为何仅依赖手动测试远远不够,并探讨了如何构建更全面的移动测试体系。
文章对多种测试策略进行了权衡:手动测试擅长发现 UI 与交互问题,但难以扩展;UI 测试可并行运行大规模流程,但维护成本高;快照测试能捕获视觉回归,却需维护参考图像库。作者建议采用混合策略——以单元测试和 UI 测试覆盖 90% 的功能,用手动测试验证真实网络环境和视觉细节,并将 UI 测试设为可选或定期运行,以避免阻塞开发流程。
在本文中,Jacob Bartlett[13]用多个示例探讨了如何借助 swift-subprocess[14]——一个旨在以 Swift 的现代特性取代老旧 Process(NSTask)API、简化进程管理的新库——改善 Swift 的脚本化编程体验。对于简单脚本而言,swift-subprocess 仍显笨重:必须创建完整的 SPM 项目,首次运行的依赖解析与编译开销让人怀疑这是否还称得上“脚本”。但在更复杂的自动化工作流(如 CI/CD 流程)中,Swift 的类型安全、模块化与可维护性则展现出优势,虽不如 Bash 精简,却更利于组织与复用。
Jacob 指出,在 LLM 辅助编程时代,Bash 脚本的边际成本几乎为零,且模型对 Bash 的掌握远超 Swift。是否采用 swift-subprocess,应基于实际需求,而非追求“用 Swift 统一所有工具链”的理想。
在过去的六个月中,Bruno Valente Pimentel[16]完成了三个应用的 Swift 6 并发迁移,他在本文中分享了那些文档里不会提及的“血泪教训”。Bruno 揭示了几个关键陷阱:@MainActor只保护同步访问,await之后的世界充满未知;Actor 重入性会引发隐蔽的竞态,需以“任务去重”的方式规避;而过度追求代码洁癖(强制 Sendable)会拖慢进度,可先用 @unchecked Sendable、@preconcurrency解锁开发,再逐步还债。
作者的感悟是:目标不是完美,而是创造比昨天更好的可用软件。
在 WWDC 2025 中,苹果为 TextEditor 带来了期待已久的富文本支持,让开发者可以直接使用 AttributedString 在 SwiftUI 中编写和编辑样式化文本。Alfonso Tarallo[18]在文中演示了从基础到编辑交互(选区、属性变换)的完整流程,并特别指出 transformAttributes(in:) 的设计巧妙:它以 inout 方式处理选区,自动合并相邻属性片段,从而避免文本碎片化。
TextEditor 的富文本能力高度依赖于 Foundation 层面对 AttributedString 的重大增强。正如 WWDC Session 中 Jeremy 所强调的,AttributedString 的索引是“一条穿过树的路径”,这种设计虽强大,却也更复杂。要真正用好这一特性,开发者不仅需要学习新 API,更要理解一种全新的文本处理范式。
单例作为“全局可变状态”,在 Swift Concurrency 的严格模型下成了棘手难题。Matt Massicotte[20]提供了一份务实的迁移指南,其核心理念是——“向编译器如实表达并发事实”(expressing truth)。
文章系统分析了多种处理方式:如果类型已具备线程安全机制,可使用 @unchecked Sendable如实声明;若主要在主线程访问,@MainActor是最诚实且高效的选择。而将类直接改为 actor 或使用自定义全局 actor 虽然能彻底隔离状态,却往往导致过度工程化。Matt 建议开发者与其掩盖现有并发访问模式,不如明确告诉编译器实际情况,让隐形风险显性化。
几天前的一个 Reddit 讨论[21]引发了热烈争论,Matt 也参与其中。这篇文章是他对该话题的系统性回应,将“如实表达”的原则贯穿始终。
虽然 Apple 明确将 Swift Concurrency 作为未来方向,但许多开发者在从 Combine 迁移后都感受到代码可读性的下降——原本简洁的响应式管道,变成了冗长的 for await循环与手动任务管理。为此, William Lumley[23]开发了 AsyncCombine,一个基于 AsyncSequence 和 Swift Observation 框架的轻量库。它在保留 async/await 原生特性的同时,重新带回了 Combine 风格的操作符,使开发者能够继续使用熟悉的 sink、assign、store(in:)等 API,编写出更直观、可组合的异步代码。
在处理复杂的异步数据流时,我依然偏爱 Combine 的管道式表达——它让数据变换的意图一目了然。正如 William 在 AsyncCombine: Because Async Code Shouldn't Be Ugly[24]中所说:强大的功能与优雅的代码并非互斥。
如果你觉得这份周报或者我的文章对你有所帮助,欢迎 点赞、赞赏,并将其 转发给更多的朋友。
参考资料
[1]
weekly.fatbobman.com: https://weekly.fatbobman.com
[2]
肘子的 Swift 记事本: https://fatbobman.com
[3]
Discord: https://t.ly/gzxeh
[4]
SwiftUI 应用热重载方案 (Hot Reloading SwiftUI Apps): https://l.fatbobman.com/w0107-01
[5]
Daniel Hooper: https://x.com/danielchooper
[6]
精通 UITableViewDiffableDataSource: https://l.fatbobman.com/w0107-02
[7]
Kingnight (Jinkai): https://github.com/kingnight
[8]
iPhone 17 屏幕尺寸 (iPhone 17 Screen Sizes): https://l.fatbobman.com/w0107-03
[9]
Keith Harrison: https://x.com/kharrison
[10]
超越 QA:移动测试策略 (Beyond QA: Mobile Testing Strategies): https://l.fatbobman.com/w0107-04
[11]
Tjeerd in ’t Veen: https://x.com/tjeerdintveen
[12]
用 Swift Subprocess 实现自动化 (Automate All the Things with Swift Subprocess): https://l.fatbobman.com/w0107-05
[13]
Jacob Bartlett: https://x.com/jacobtechtavern
[14]
swift-subprocess: https://github.com/swiftlang/swift-subprocess?utm_source=fatbobman%20weekly%20issue%20107&utm_medium=web
[15]
Swift 并发:那些早该知道的事 (Swift Concurrency: What I Wish Someone Had Told Me): https://l.fatbobman.com/w0107-06
[16]
Bruno Valente Pimentel: https://www.linkedin.com/in/valentebruno/
[17]
SwiftUI TextEditor 富文本编辑 (Using Rich Text in the TextEditor with SwiftUI): https://l.fatbobman.com/w0107-07
[18]
Alfonso Tarallo: https://www.linkedin.com/in/fonztara/
[19]
在 Swift Concurrency 中处理单例 (Singletons with Swift Concurrency): https://l.fatbobman.com/w0107-10
[20]
Matt Massicotte: https://mastodon.social/@mattiem
[21]
Reddit 讨论: https://www.reddit.com/r/swift/comments/1oa7em5/swift_6_concurrency_singletons/
[22]
AsyncCombine: https://l.fatbobman.com/w0107-08
[23]
William Lumley: https://bsky.app/profile/will-lumley.bsky.social
[24]
AsyncCombine: Because Async Code Shouldn't Be Ugly: https://l.fatbobman.com/w0107-09