利益相关声明:作者与文中产品有直接的利益相关(开发者、自家产品等)

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 语言与框架

Swift,编程语言,类似 JavaScript、TypeScript、Python... 可以用 Swift 写 App 也可以写命令行工具、服务端程序,或者一些底层逻辑。

真正决定界面样式、窗口管理、按钮显示的,是 UI 框架,比如:SwiftUI、AppKit、UIKit,它们的关系其实也很简单:

SwiftUI 更新、更轻量,是目前苹果官方主推的、跨平台的 UI 框架;AppKit / UIKit 则是更传统、更底层、更可控的原生 UI 框架。

平台原生 UI 框架新一代 UI 框架
macOSAppKitSwiftUI
iOSUIKitSwiftUI
iPadOSUIKitSwiftUI
tvOSUIKit / TVUIKitSwiftUI
watchOSWatchKitSwiftUI

 

SwiftUI:快速、清晰,适合页面型 UI

SwiftUI 特色

如果你要做的是工具类 App,SwiftUI 往往是很好的起点。

它最大的优势是开发者友好,开发效率高,比如:设置页、登录页、授权页、表单、列表、引导流程、简单弹窗,这些界面用 SwiftUI 写起来很舒服,只需要描述状态和界面的关系。状态变化,UI 更新;组件拆分,组合界面;声明结构,框架处理刷新。

比如某个用户是否是 Pro,某个开关是否打开,某个弹窗是否显示,SwiftUI 都可以很自然地根据状态变化刷新界面。

AppKit:复杂、底层,适合系统型 UI

AppKit 特色

AppKit 的优点刚好在另一个方向,它写起来复杂(封装程度低),对新手不友好(同样的功能要写更多代码),但它更接近 macOS 本身:

AppKit 概念负责内容
NSWindow窗口
NSView视图
NSCollectionView复杂网格和集合视图
NSMenu菜单
NSStatusItem菜单栏图标
NSPanel浮动面板
NSVisualEffectView毛玻璃和系统视觉效果

以启动台类型的产品为例:它最核心的主界面,并非单纯的内容展示,而是涉及到非常多系统层面的逻辑:

全屏窗口、多显示器行为、窗口层级、键盘焦点、触控板手势、图标网格、Dock 和 Cmd + Tab 行为、F4 事件、后台应用逻辑……

这些东西用 SwiftUI 也可以实现,但大概率你会发现:

前 80% 很快,也很爽;最后 20% 却很慢,也很痛苦😂。因为当「样式」基本完成之后,真正麻烦的部分才刚开始:如何让它像一个 macOS 系统应用一样运行。窗口层级、焦点管理、动画时机、触控板手势、多显示器行为,这些都不是单纯调 UI 就能解决的。你不得不通过各种桥接接口把 SwiftUI 和 AppKit 接在一起,而桥接一多,代码复杂度、状态同步成本和不可预期的问题也会一起增加。

为什么 LaunchOS 最终选择了 AppKit?

LaunchOS 主界面

作为一款启动台类型的项目,它看起来很简单:显示应用图标,点击打开。

但其实展示图标这部分,虽然视觉感知上差不多可占 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,但未来将会是一个桌面助手类的超级应用。

感谢大家时间,下期见~