TL;DR My rule of thumb for macOS tools is simple: if it's mostly content display and basic interaction, SwiftUI is fast and good. The moment it approaches the detail density of a desktop-grade productivity tool (window management, menu bar, shortcuts, drag and drop, fine scrolling), bring AppKit back early — it's not legacy baggage, it's a capability boundary. In practice I work in three layers: SwiftUI handles page structure and state display, AppKit handles windows, menus, and focus — the desktop details users actually feel — and the shared layer holds the data models and Core ML inference. One thing to remember: native feel isn't looking like macOS; it's the user never noticing "this is a wrapper" when working the edges.

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

Layering in Practice
  • 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 负责窗口、菜单、焦点这些用户真正感知得到的桌面细节,数据模型和 Core ML 推理放在共享层。记住一点:原生体验不是看起来像 macOS,而是用户在边角操作时察觉不到"这是个壳"。

为什么这个问题总会出现

做 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,界面都只关心状态,而不是模型生命周期。