Issue #152

当 Mac mini 的价格不再 mini

Cover for Weekly Issue 152

Photo by Amanz on Unsplash

上月底,苹果发布了新的 Mac mini 和 Mac Studio。除了强悍的性能更新,明显上涨的价格同样给人带来了不小的震撼。内存与存储成本上涨无疑是本轮涨价的重要原因,但在 AI 时代,开发者对硬件的需求也在悄然发生变化。更大的内存、更高的存储容量,不断推高我们心目中“够用配置”的标准,最终也让实际购买价格变得更加夸张。

过去几个月,开发中最让我头痛的一件事,是 MacBook Pro 风扇持续转动带来的噪音。过去多年的使用中,只有在少数高负载场景下,我才会明显意识到风扇的存在。但到了 AI Agent 时代,风扇常转几乎成了家常便饭。受限于机身空间和风扇尺寸,笔记本在持续高负载下产生的噪音,往往也比 Mac mini 这类桌面设备更容易让人感到不适。

与此同时,我发现 MacBook 在自己的工作流中似乎也没有以前那么不可替代了。除非有特殊需要,短途出差时,手机和平板已经足以应付不少 Vibe Coding 场景。即便仍然需要一台笔记本,一台更轻、配置更低的设备似乎也完全够用。因此,我开始认真考虑把主力开发设备从 MacBook Pro 转移到 Mac mini 或 Mac Studio 上。

问题随之而来:作为主力开发设备,内存容量必然是一道硬门槛。尽管我几乎没有运行本地 LLM 的需求,但既然是一次设备更新,新机器的内存至少应该明显高于当前的 64GB,才能让我感受到足够的升级价值。如此一来,采用 M6 或 M5 Pro 的 Mac mini 基本就被排除了,剩下的选择只有 M5 Max 和 M5 Ultra 的 Mac Studio。

有趣的是,两款机型在 64GB 之上的下一档内存分别是 128GB 和 96GB,而最终价格却相差无几。一个给更多内存,一个给更强芯片。即便我平时并不算有选择困难,这次也确实有些犯难。

与此同时,OpenClaw 的风行让不少原本并不关注 Mac mini 的消费者开始将目光投向这台小机器。据报道,OpenAI 也采购了数万台 Mac mini 和 Mac Studio,用于强化学习和 Computer-use Agent 的训练。AI 带来的需求增长一度远超苹果的预期,再加上内存供应和先进制程产能的压力,让 Mac mini 和 Mac Studio 在过去几个月一直处于供不应求的状态。新一代产品发布之后,想要尽快拿到自己心仪的配置,依然不是一件容易的事。

AI 带来的效率提升或许还没有在整个社会中充分显现,但它对算力、内存和存储资源的争夺,已经率先反映到了硬件市场。从零部件到整机,大量消费级硬件都在承受新的价格压力。过去那种隔几年用差不多的钱,就能买到一台明显更强电脑的更新节奏,至少在现阶段似乎越来越难维持了。

但更有意思的是,我们又不能把这一切完全归咎于涨价。AI 在推高硬件成本的同时,也改变了我们的开发方式,并悄悄抬高了我们对一台“够用电脑”的定义。硬件变贵了,我们想要的也更多了。

希望未来某一天,我们还能找回那个不用做太多心理建设,就能轻松选购一台 Mac mini 的时代。

原创

SwiftData:优化从建模开始

数据集一大,SwiftData 的列表就开始卡。这是这几年里我听到最多的性能抱怨。开发者的第一反应通常会指向 SwiftUI 的 List。它确实有责任,但并非最主要的问题。进一步分析会发现,真正拖垮性能的不只是加载时间,巨大的内存占用同样不容忽视。本文将聊聊 SwiftData 为什么会出现这些问题,以及优化为什么应该从数据建模开始。

SwiftData 中一些看似缺失的能力,或许本就是有意为之:通过减少暴露的 API 和逻辑层来降低学习曲线。因此,在优化 SwiftData 应用时,也应该适当放下 Core Data 时代形成的一些惯性思维。

近期推荐

十年终章:Swift Talk 宣布停更 (The End of Swift Talk)

在开始十年、完成 500 期节目后,⁠Chris Eidhof 和 ⁠Florian Kugler 宣布 Swift Talk 正式结束。从 2016 年 6 月开始,Swift Talk 几乎完整陪伴了 Swift 走向成熟的过程,也见证了 SwiftUI 从诞生到逐渐成为 Apple 平台 UI 开发核心框架的这些年。两人通过一系列深入而又充满实验性的节目,探索了 Swift、SwiftUI、布局、动画、并发以及大量很难在普通教程中看到的底层问题。官方表示,希望在今年年底让完整的 500 多期节目归档能够继续提供给社区。

对我而言,objc.io 和 Swift Talk 一直是 Swift 社区中非常特别的存在。Chris 和 Florian 很少满足于告诉开发者一个 API “应该怎么用”,而是习惯通过实验、重构甚至重新实现,去追问框架为什么会这样工作。这种探索方式影响了许多 Swift 开发者,也包括我自己。感谢 Chris 和 Florian 这些年来为 Swift 社区投入的时间、知识与好奇心,也感谢 Swift Talk 留下的这份珍贵档案。


Swift 官方 8 月报 (What’s new in Swift: August 2026 Edition)

Swift 官方发布了 8 月生态月报,由 ⁠Simon Leeb 和 ⁠Dave Lester 整理,汇总了近期值得关注的社区项目、Package 更新和 Swift Evolution 进展。其中最让我感兴趣的是 Swift 在 Web 方向上的推进:Simon Leeb 展示了一个 ⁠Full-Stack Swift on Cloudflare Demo,浏览器端通过 ElementaryUI 和 WebAssembly 运行 Swift,后端则运行在 edge worker 上,两端还能共享消息类型。从 Embedded Swift、Wasm 到越来越完善的跨平台工具链,Swift 的使用边界正在继续向 Apple 平台之外扩展。

语言层面,刚刚获批的 ⁠⁠Iterable 也很值得关注。Sequence 在遍历时会逐个产生独立的元素值,但对于 SpanInlineArray 等可能包含 non-copyable 元素的数据结构,这套模型并不适用。Iterable 允许直接借用而非复制元素进行遍历,让这些数据结构也能拥有自然的遍历方式。它看起来只是一个新的遍历抽象,却也是 Swift ownership 能力逐渐从语言底层走向日常 API 设计的又一个体现。


在嵌入式设备上运行 OpenSwiftUI (OpenSwiftUI on ESP32-C3)

上面的 Swift 月报展示了 Swift 正在不断突破 Apple 平台的边界,而 OpenSwiftUI 开发者 ⁠Kyle Ye 最近的一次尝试,则给这个趋势提供了一个很直观的例子。在收到 TraeAI 赠送的 ESP32-C3 开发设备后,Kyle 完成了自己的第一个 Embedded Swift 项目:将 OpenSwiftUI 的嵌入式版本部署到这块采用 RISC-V 架构的微控制器上,并在 240 × 320 的 LCD 上使用我们熟悉的 View@ViewBuilderTextImageVStackHStackZStack 等 API 构建界面,甚至 @State 也能响应实体按键并触发界面更新。

这个实验利用 Embedded Swift 编译原生 RISC-V 代码,由 OpenSwiftUI 负责视图组合和布局,再通过一个很薄的渲染边界将绘制交给 LVGL 和底层硬件。换句话说,从声明式 View、布局计算、状态更新到最终像素输出,一套精简但完整的 UI 链路已经建立起来。


Swift 跨平台实践:多平台下的 C++ 依赖管理 (Multiplatform Swift, with C++ dependencies via XCFramework, apt and vcpkg)

一个 Swift 应用能否真正实现跨平台,很多时候取决于其背后的 C/C++ 依赖能否跟着跨平台。⁠Harald Achitz 以自己的 ZeroMQ Swift bindings 为例,展示了一个同时支持 macOS、Linux 和 Windows 的 Swift/C++ 项目如何组织原生依赖:Apple 平台使用 XCFramework,Linux 使用系统 package,Windows 则通过 vcpkg 安装 ZeroMQ。


在 iOS 模拟器间实现虚拟蓝牙通信 (Connecting two iOS simulators over BLE)

CoreBluetooth 在 iOS Simulator 中完全不可用,这让 BLE App 的开发和测试长期依赖真机。⁠⁠Kyle Browning 在开发 ⁠BLESwift 2.0 时换了一种思路:Simulator 中的中心设备(Central)和外围设备(Peripheral)不再调用 CoreBluetooth,而是通过 localhost TCP 将操作转发给运行在 Mac 上的 bleswift-provider,由它构建一个“虚拟无线电”。这样,两个 Simulator 就能像两台真实 BLE 设备一样完成发现、连接、读写和 notification,甚至还可以通过 passthrough 模式借用 Mac 的蓝牙,与真实 BLE 设备通信。

比 BLE 本身更让我感兴趣的是这种测试范式:当 Simulator 缺少某项系统或硬件能力时,不一定要在 App 内到处添加 mock,而是可以在系统能力与业务代码之间建立可替换的 backend,再通过 Mac 上的代理进程重建一个可控的外部世界。这种设计不仅解决了“Simulator 缺少某些系统或硬件能力”的问题,也让原本高度依赖真实环境的功能更容易进入自动化测试和 CI。


探索 SwiftUI 全新的任意容器拖拽排序 API (Reorder all the things in SwiftUI)

SwiftUI 长期以来没有提供在任意容器中实现拖拽排序的通用 API,这个遗憾在 WWDC 2026 后得到了解决。⁠⁠Alexander Logan 介绍了 SwiftUI 新的 reordering API。通过 reorderablereorderableContainer 等,开发者可以直接声明哪些内容可以被重新排序以及对应的数据模型,让拖拽排序不再局限于 List,也不必自己通过 DropDelegate 管理拖拽位置和数据更新。更重要的是,新 API 提供了更高层的交互语义,将“reordering”从 drag & drop 这一具体实现方式中抽离出来。开发者描述的是“这些内容可以重新排序”,至于通过鼠标、触控还是其他输入方式完成操作,则可以更多地交给系统处理。


Swift Charts 进阶:如何绘制多层旭日图 (Building a sunburst diagram in Swift Charts)

旭日图(Sunburst Diagram)是一种用同心圆环展示层级数据的图表,例如从“工作”到“开发”,再到某个具体项目,越向外代表越细的数据层级。⁠⁠Matthaus Woolard 展示了如何利用 Swift Charts 的 SectorMark,从普通饼图开始,逐步构建一个包含三层数据的旭日图。这个实现也很好地展示了 Swift Charts 的灵活性:当框架没有直接提供某种图表时,可以将 SectorMark 等 Mark 视为更基础的可视化原语,通过自行计算角度区间和数据映射来构建更复杂的图表。

工具

CoreDataBrowser:快速查看 Simulator 中的本地数据

调试 Core Data 或 SwiftData 应用时,通常需要先在层层嵌套的 Simulator 目录中找到对应的数据文件,再用 SQLite 管理器打开并浏览数据。由 ⁠Csaba Turdesan 开发的 CoreDataBrowser 尝试把这个过程变得简单:选择当前启动的模拟器后,它会自动查找应用容器中的 Core Data、SwiftData 以及 UserDefaults 数据源,并通过原生 macOS 界面统一呈现。

CoreDataBrowser 支持查看表与记录、搜索并高亮匹配内容,也能对部分二进制数据(BLOB)尝试解析 NSKeyedArchive、JSON、Property List 和 UTF-8 文本。工具体量很小(2.5 MB),并且⁠源码公开

相关周报

订阅 Fatbobman 周报

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

立即订阅