Why This Question Keeps Coming Up
Building macOS tools, SwiftUI’s first impression is always great: fast to write, live previews, clean structure. But the moment you touch window management, menu bar behavior, complex lists, shortcuts, drag and drop, and fine scrolling control, AppKit comes back to the desk sooner or later.
My rule of thumb is simple now: if the requirement is typical content display and basic interaction, SwiftUI is efficient enough; if the requirement starts approaching the detail density of a “desktop-grade productivity tool,” accept early that AppKit isn’t legacy baggage — it’s a capability boundary.
My Current Layering Habit
- SwiftUI: page structure, forms, state-driven display
- AppKit: windows, menus, input focus, bridging complex controls
- Shared layer: data models, commands, file system, Core ML inference
The nice thing is you don’t have to pick a side up front. SwiftUI handles speed and expressiveness; AppKit handles the “desktop-native details” users actually feel.
When to Go Back to AppKit Decisively
- You need stable multi-window behavior and lifecycle control
- You’re building complex tables, sidebars, command menus, a shortcut system
- You start working around scrolling, focus, text selection, drag and drop, or list performance
Native feel isn’t looking like macOS — it’s the user not noticing “this is a wrapper” when working the edges. Dev note
On Core ML
If the tool needs on-device inference, I put model calls and caching strategy in a standalone service layer and don’t stuff inference logic directly into views. Then, whether the front is SwiftUI or AppKit, the UI only cares about state, not model lifecycle.
What’s actually worth the time isn’t “how to write all the code in SwiftUI” — it’s how to make users feel it’s just a natural macOS tool.
FAQ
Do I have to pick between SwiftUI and AppKit?
No need to pick a side up front. My layering habit: SwiftUI does page structure, forms, and state-driven display; AppKit handles windows, menus, input focus, and bridging complex controls; data models, commands, file system, and Core ML inference live in the shared layer.
When should I decisively go back to AppKit?
Three signals: you need stable multi-window behavior and lifecycle control; you’re building complex tables, sidebars, command menus, a shortcut system; you start working around scrolling, focus, text selection, drag and drop, or list performance.
What counts as truly native feel?
Not looking like macOS — the user not noticing “this is a wrapper” when working the edges.
Where should Core ML inference code go?
Prefer a standalone service layer, together with the caching strategy, not stuffed directly into views. Then, whether the front is SwiftUI or AppKit, the UI only cares about state, not model lifecycle.
为什么这个问题总会出现
做 macOS 工具时,SwiftUI 的第一印象总是非常好:写得快、预览直接、结构清晰。但只要开始碰窗口管理、菜单栏行为、复杂列表、快捷键、拖拽和精细滚动控制,AppKit 迟早会重新回到桌面上。
我现在的判断标准很简单:如果需求是典型的内容展示和基础交互,SwiftUI 足够高效;如果需求开始接近”桌面级生产力工具”的细节密度,就要尽早接受 AppKit 不是历史包袱,而是能力边界。
我现在的分层习惯
- SwiftUI:页面骨架、表单、状态驱动展示
- AppKit:窗口、菜单、输入焦点、复杂控件桥接
- 共享层:数据模型、命令、文件系统、Core ML 推理
这样做的好处是不需要一开始就站队。SwiftUI 负责速度和表达力,AppKit 负责那些用户真正会感知到的”桌面原生细节”。
什么时候该果断回到 AppKit
- 你需要稳定的多窗口行为和生命周期控制
- 你要做复杂表格、侧边栏、命令菜单、快捷键体系
- 你在滚动、焦点、文本选择、拖拽、列表性能上开始频繁绕路
原生体验不是看起来像 macOS,而是用户在边角操作时不会察觉到”这是个壳”。 开发笔记
关于 Core ML
如果工具里要接本地推理,我会优先把模型调用和缓存策略放在独立服务层,不把推理逻辑直接塞进视图。这样无论前面是 SwiftUI 还是 AppKit,界面都只关心状态,而不是模型生命周期。
真正值得花时间优化的,不是”怎么把所有代码都写成 SwiftUI”,而是怎样让用户感觉它就是一款自然的 macOS 工具。
常见问题
SwiftUI 和 AppKit 必须二选一吗?
不用一开始就站队。我的分层习惯是:SwiftUI 做页面骨架、表单、状态驱动展示;AppKit 管窗口、菜单、输入焦点、复杂控件桥接;数据模型、命令、文件系统、Core ML 推理放在共享层。
什么时候该果断回到 AppKit?
三个信号:需要稳定的多窗口行为和生命周期控制;要做复杂表格、侧边栏、命令菜单、快捷键体系;在滚动、焦点、文本选择、拖拽、列表性能上开始频繁绕路。
什么叫真正的原生体验?
不是看起来像 macOS,而是用户在边角操作时不会察觉到”这是个壳”。
Core ML 推理代码应该放哪?
优先放在独立服务层,和缓存策略一起,不要直接塞进视图。这样无论前面是 SwiftUI 还是 AppKit,界面都只关心状态,而不是模型生命周期。