"SwiftUI or AppKit is the wrong question. Which one owns the window, and which one draws the leaves?"
The Family's Mac Apps Use All Four
Tutorials present SwiftUI and AppKit as a choice. Real Mac apps combine them, and the useful question is where the boundary sits. The family's Mac apps land on four distinct shapes:
- AppKit only. A dual-pane file workbench and a terminal are AppKit from top to bottom:
NSTableViewandNSCollectionView,NSSplitViewController, a custom tab strip, fine-grained keyboard handling. Nothing in them needed SwiftUI, and several things needed control SwiftUI does not expose. - AppKit with SwiftUI leaves. A prose editor built on the AppKit text system, and several menu-bar utilities, keep AppKit as the application skeleton and host SwiftUI for the parts SwiftUI is great at — settings panes, forms, small panels — through
NSHostingVieworNSHostingController. - SwiftUI app with AppKit hosts. A video player, a creative sidecar and an agent client use a SwiftUI
Appand windows, and wrap one heavy native view each — a video layer, a web view — inNSViewRepresentable. - Pure SwiftUI. A small launcher is a
MenuBarExtra, aWindowand a thin app-delegate adaptor. For a surface that small, SwiftUI is simply less code.
How to Choose
- Text is the product (an editor, a terminal) → AppKit owns the view. The text system's input methods, marked-text composition and undo are where SwiftUI's abstractions leak first.
- Custom window chrome — tinted title bars, your own tab strip, nested split views with remembered sizes → AppKit owns the window.
- Mostly standard windows around one special view → SwiftUI app, AppKit host for that view.
- Forms, settings, lists of simple rows → SwiftUI, wherever it is hosted.
- A menu-bar utility with a popover and a settings window → either pure SwiftUI with
MenuBarExtra, or AppKitNSStatusItemwhen you need precise control over the item, global hotkeys and panels.
The shapes are not a ladder of maturity. The family's most complex app is AppKit-only and its smallest is pure SwiftUI; both are correct. What goes wrong is drifting between shapes without deciding: a SwiftUI view that owns an AppKit object's lifetime without anyone noticing, or an AppKit app that grows ad-hoc SwiftUI islands with their own copies of state. The rest of this track is about the seams.