Last Week on My Mac: SwiftUI wrangling
In just two months, SwiftUI will be five years old. First released for macOS Catalina in 2019, it’s hard to believe that it’s only two years younger than APFS. Although I’ve been happily developing my apps using AppKit, one of the major components of Cocoa, I’ve been trying to recreate my app Skint using SwiftUI, so I can create a widget for it.
Way back in Classic Mac OS, Apple introduced what was then a class library named MacApp. In 1989 it became the most straightforward way of creating full-featured apps for the Mac, and came with full source code. Sadly, with Mac OS 9.0, MacApp went the way of C++, and in any case was soon overwhelmed by the coming of Mac OS X. When that was released in 2001, it came with a new set of what then became termed frameworks, including AppKit. Those were all closed source, though.
AppKit turned five years old midway between 10.4 Tiger and 10.5 Leopard, by which time it was large and mature. For instance, support for rich text in the form of what Apple terms Attributed Strings had been provided from its initial release, and Apple’s Attributed String Programming Guide was already more than four years old.
As Apple’s devices started to proliferate, their operating systems acquired their own equivalents of AppKit, in the case of iOS with UIKit. Although AppKit and UIKit have much in common, they’re sufficiently different to make porting apps between them burdensome enough to be deterrent. In 2019, Apple announced one route by which developers could generate macOS versions of iPadOS apps using Mac Catalyst, formerly known internally as Marzipan. At the same time, Apple released the first version of SwiftUI, a completely new approach to app development, intended to form native apps for all Apple’s operating systems, including visionOS as of last year.
Apple currently describes SwiftUI as the way to “declare the user interface and behavior for your app on every platform”, rather than claiming it’s a replacement for AppKit on macOS. It elaborates that “you can integrate SwiftUI views with objects from the UIKit, AppKit, and WatchKit frameworks to take further advantage of platform-specific functionality.” However, SwiftUI has greater ambitions: in Apple’s words, you “define your app structure using the App protocol”, which goes much deeper than the user interface.
As a five year-old, SwiftUI is in many respects precocious, and goes much further than AppKit did for many years. I wish there was a single point of reference that I could give, listing some of these remarkable features, including keyframe animation, map display, Apple Wallet access, and a video player. Rather than following the command-based or imperative model adopted by MacApp and AppKit, SwiftUI is declarative. Instead of code opening a window, in SwiftUI the components within the window are stated, and the app gets on with the task of assembling and displaying those components. Although that isn’t incompatible with an imperative programming approach, their chalk and cheese don’t make particularly good pizzas.
In assessing how far this five year-old has progressed, I’ve been both more mundane and practical. I start with four key types of view that are used widely across macOS apps and must be well-supported: plain text display and editing, styled text display and editing (e.g. Rich Text, formed from good old Attributed Strings), PDF and HTML rendering and display. Without those, basic tools like a Help book become impossible.
As SwiftUI stands, it can manage just one of those four key types of view, plain text. The other three can only be invoked practically by integrating their AppKit versions. Perhaps I have misunderstood Apple, but none of those three could be dismissed as “platform-specific functionality”, and each is also supported in iOS and iPadOS.
Another fundamental problem I’ve run into is the app life cycle. Many Mac apps start with a brief initialisation phase, during which they might check required resources, look online for app updates, and load app-wide preferences and menus. Once those are complete or under way, the app turns to the task of opening documents and their windows, perhaps. Then, when the user quits the app, there’s a completion phase in which any last changes to settings are made, and the app gracefully exits. When using AppKit, these are normally accomplished in an AppDelegate, but Apple cautions against that for SwiftUI. In a box marked Important, it states: “Manage an app’s life cycle events without using an app delegate whenever possible.”
For someone porting an app from AppKit to SwiftUI, that comes as a bit of a bombshell, and implies that Apple hasn’t worked out exactly how to convert common AppDelegate functions into SwiftUI’s App protocol. After five years, that’s more than a little unhelpful.
My biggest problem with SwiftUI is its fundamental regression in terms of user interface design and development.
One revolution saved the Mac in its early years, desktop publishing, or DTP. Forty years ago, laying up and typesetting pages relied on languages like Donald Knuth’s TeX. When you were designing pages, you marked up the text using the TeX language, passed your document through a compiler to generate a DVI, then displayed that. While there are still some compelling reasons for using TeX and its descendant LaTeX, the DTP revolution grew from WYSIWYG tools. You created designs using Aldus Freehand, inserted them into laid up pages in Aldus PageMaker, then printed those out on your Apple LaserWriter. What you saw on your Mac’s display was identical to what you got on paper, and not a single line of code was written because you created the pages directly.
For all its faults, Interface Builder in Xcode is a WYSIWYG user interface builder. SwiftUI instead relies on the TeX model of writing code and iteratively adjusting that until its preview looks right. It has taken us forty years to go round full circle, and uninvent WYSIWYG.
SwiftUI resources
The closest resource to a complete guide and reference to SwiftUI is the SwiftUI Lab’s app A Companion for SwiftUI, from the App Store. It might appear expensive, but it’s worth more than all the other resources put together.
Apple’s documentation on SwiftUI is extensive but ultimately of limited use for macOS. The Companion above should be your first port of call.
There are many books about SwiftUI, but almost all are primarily or exclusively about iOS. The following have particular virtues that make them stand out for those targeting macOS:
Sarah Reichelt (2022) macOS by Tutorials, macOS App Development for iOS Developers, ISBN 978 1 95032 566 5.
Juan C Catalan (2023) SwiftUI Cookbook, 3rd edition, packt, ISBN 978 1 80512 173 2.
Peter Friese (2023) Asynchronous Programming with SwiftUI and Combine, Apress. ISBN 978 1 4842 8571 8.
Chris Eidhof and Florian Kugler (2023) Thinking in SwiftUI, objc. ISBN 979 8 3972 4668 2.
Chris Eidhof and others (2022) Advanced Swift, objc. ISBN 979 8 4207 8952 0.
I have yet to discover any open-access (rather than subscription) website that specialises in SwiftUI for macOS, but am open to your suggestions, please.