SwiftUI 的抽象层更高,它擅长用更少的代码写出优雅的界面;但在一些复杂的 macOS 场景里,这层抽象也会带来额外的损耗。
AppKit 写起来更重,却让开发者从更底层接管事件、动画或生命周期的控制权。某些时候,更多的代码,反而更少走弯路,获得更轻量的体验。
大家好👋,
我是章萧醇(Jimmy),半年前曾在这篇文章 《LaunchOS:将原生体验的启动台带回 macOS 26》和大家第一次见面,这个产品的目标是在 macOS 26+ 的系统上,提供和经典 Launchpad 几乎一致甚至更优雅的使用体验。
今天,是想借助这款产品,聊聊我们过去在产研过程中,经受的 “苦难” 以及总结的经验(一声长叹):
本文的核心讨论:SwiftUI or AppKit?
其实在过去 2 个多月里,我们一直在重构 LaunchOS。
V1 主要基于 SwiftUI 完成,其流畅的体验与细节打磨,逐步成为大家心目中最佳的启动台替代方案,但其实我们自己发现,在某些场景上,我们正在触摸 SwiftUI 的天花板:我们不得不为了一个很小的功能改进,反复寻找优化空间来提升它的性能表现,而每一次优化所消耗的时间,已远远大于我们开发功能花费的时间。
纠结了很久,我们还是决定把核心部分推倒重来,转向 AppKit...
做 mac 应用时,什么时候适合 SwiftUI,什么时候用 AppKit?
从基础概念说起:Swift、SwiftUI、AppKit、UIKit
避免大家概念混淆,先了解下基本概念,资深前辈请绕行。

Swift,编程语言,类似 JavaScript、TypeScript、Python... 可以用 Swift 写 App 也可以写命令行工具、服务端程序,或者一些底层逻辑。
真正决定界面样式、窗口管理、按钮显示的,是 UI 框架,比如:SwiftUI、AppKit、UIKit,它们的关系其实也很简单:
SwiftUI 更新、更轻量,是目前苹果官方主推的、跨平台的 UI 框架;AppKit / UIKit 则是更传统、更底层、更可控的原生 UI 框架。
| 平台 | 原生 UI 框架 | 新一代 UI 框架 |
|---|---|---|
| macOS | AppKit | SwiftUI |
| iOS | UIKit | SwiftUI |
| iPadOS | UIKit | SwiftUI |
| tvOS | UIKit / TVUIKit | SwiftUI |
| watchOS | WatchKit | SwiftUI |
SwiftUI:快速、清晰,适合页面型 UI

如果你要做的是工具类 App,SwiftUI 往往是很好的起点。
它最大的优势是开发者友好,开发效率高,比如:设置页、登录页、授权页、表单、列表、引导流程、简单弹窗,这些界面用 SwiftUI 写起来很舒服,只需要描述状态和界面的关系。状态变化,UI 更新;组件拆分,组合界面;声明结构,框架处理刷新。
比如某个用户是否是 Pro,某个开关是否打开,某个弹窗是否显示,SwiftUI 都可以很自然地根据状态变化刷新界面。
AppKit:复杂、底层,适合系统型 UI

AppKit 的优点刚好在另一个方向,它写起来复杂(封装程度低),对新手不友好(同样的功能要写更多代码),但它更接近 macOS 本身:
| AppKit 概念 | 负责内容 |
|---|---|
| NSWindow | 窗口 |
| NSView | 视图 |
| NSCollectionView | 复杂网格和集合视图 |
| NSMenu | 菜单 |
| NSStatusItem | 菜单栏图标 |
| NSPanel | 浮动面板 |
| NSVisualEffectView | 毛玻璃和系统视觉效果 |
以启动台类型的产品为例:它最核心的主界面,并非单纯的内容展示,而是涉及到非常多系统层面的逻辑:
全屏窗口、多显示器行为、窗口层级、键盘焦点、触控板手势、图标网格、Dock 和 Cmd + Tab 行为、F4 事件、后台应用逻辑……
这些东西用 SwiftUI 也可以实现,但大概率你会发现:
前 80% 很快,也很爽;最后 20% 却很慢,也很痛苦😂。因为当「样式」基本完成之后,真正麻烦的部分才刚开始:如何让它像一个 macOS 系统应用一样运行。窗口层级、焦点管理、动画时机、触控板手势、多显示器行为,这些都不是单纯调 UI 就能解决的。你不得不通过各种桥接接口把 SwiftUI 和 AppKit 接在一起,而桥接一多,代码复杂度、状态同步成本和不可预期的问题也会一起增加。
为什么 LaunchOS 最终选择了 AppKit?

作为一款启动台类型的项目,它看起来很简单:显示应用图标,点击打开。
但其实展示图标这部分,虽然视觉感知上差不多可占 95%,但研发成本却只占 5% 左右。
用户对这类工具的容忍度非常低,尤其是愿意支付换取更优体验的用户,用户会天然拿它和原生的 Launchpad 比较:动画慢半拍,图标闪一下,手势不跟手,窗口出现在错误的屏幕,搜索焦点不稳定,多显示器下层级异常,都会让用户问候我们团队的家人和老人。
SwiftUI 的抽象层更高。它擅长让你用更少代码描述 UI 状态,但当你需要非常精确地控制窗口、事件、动画和生命周期时,则可能会变得很绕。
AppKit 虽然写起来更重,什么都得自己写,但它可以让你更直接地管理这些底层细节。
所以并非 SwiftUI 不好,只是对于启动台这类核心体验更偏「系统型 UI」,而不是「页面型 UI」的应用来说,不适合。
如何选?核心原则
页面型 UI 优先 SwiftUI,系统型 UI 优先 AppKit
事实上大部分 macOS App,很少需要纯 SwiftUI 或纯 AppKit,混用很常见也更合适。
| 场景 | 更适合 SwiftUI | 更适合 AppKit |
|---|---|---|
| 设置页、表单、授权页 | 是 | 否 |
| onboarding、关于页、提示弹窗 | 是 | 否 |
| 普通列表、内容展示 | 是 | 复杂场景 |
| 多窗口管理 | 简单场景 | 复杂场景 |
| Dock 行为 | 简单场景 | 是 |
| 全局行为、系统行为管理 | 能力受限 | 是 |
| 复杂鼠标、键盘、触控板事件 | 能力受限 | 是 |
| 高性能、复杂 Collection | 简单场景 | 是 |
| 快速原型 | 非常适合 | 否 |
最后
AppKit 写起来是真麻烦(捂脸哭笑),本以为两星期搞定,结果搞了 2 个多月。
LaunchOS 的 AppKit 重构版本目前还在测试阶段,可能会在解决了一些问题的基础上暂时出现了新的问题,如果您也是相关产品的受众用户,欢迎测试和反馈,我们也会从参与内测的用户中抽取高质量(有帮助)反馈送上双设备的 Pro 版许可证;
测试版下载地址:https://launchosapp.com/ 点击下载按钮下方的「下载测试版」获取最新测试版本
抽奖反馈入口:LaunchOS 设置 - 关于 - 右下角反馈按钮
一点插曲
由于重构持续时间有点久,我(产品角色)等不及一些功能优化,就自己用 Codex 写了一些,还专门挑的小功能或样式部分,结果被我研发同事吐槽得体无完肤(😂):
你提交的 PR 我看了,问题也太多了,都得重写
- 这里我抽象过方法,它又重写了一个
- 这个部分它只处理了缓存逻辑,没有做持久化
- 这个地方它将代码写在子组件里,看起来没毛病,但会导致每一次操作都要全量执行,完全没必要...
果然会代码的人用 Codex 和不会代码的人相比,用的是两个产品。但我真的很喜欢 Codex,虽然现在主形态还是 Vibe Coding 的 Agent,但未来将会是一个桌面助手类的超级应用。
感谢大家时间,下期见~
