Update: this article is now old. SwiftUI should be considered for new Mac apps, at least for most of the UI. Read more about SwiftUI usage on Alex Grebenyuk’s blog.
I have been experimenting with SwiftUI lately as I started working on a new Mac application. This new application I’m working on, which shall go unnamed and uncategorised for the moment, is going to be complex, with a complex UI including many views with sidebars, tables, image views and 3d views.
Having no previous experience with SwiftUI, not even doing a simple app nor going through one of the many tutorials available (I’m not going to link any of them as I wouldn’t know where to start), I fully committed myself to doing everything the SwiftUI way (the iOS way for the impatient). The first thing I tried to implement was a view switcher, a toolbar segmented control to select which view is active. Something like this:
This is totally impossible to do, as far as I tried. It might be possible with some incantations, but is it worth it given how easy it is to do in a Storyboard? I think this is one of the cases where it shouldn’t even be attempted, because you don’t gain much from it. So I did it with Interface Builder.
The next thing I tried to implement in SwiftUI was an info panel below the toolbar, which has mostly labels laid out in a grid fashion with vertical separators for grouping. This went extremely well and easy in SwiftUI once I got past the initial context-switch. Having all data synchronised with Combine is truly magical and I expect to keep using it everywhere. So after I finished this view, I bought into SwiftUI.
Sidebars are an important part of many Mac applications. They are used for navigating through a hierarchy of data. So naturally I wanted to experiment with making a simple one to see how SwiftUI fared. I had seen many tutorials and tried many combinations until I found one that gave me exactly what I wanted: something like a standard source list. There are several spells you need to cast to get one working properly. This is not a good sign, because it should be very transparent. What you get from SwiftUI is a very generic format to build things which can be configured to look well in iOS by default but it’s much more difficult to get a native MacOS look without tweaking lots of things. The fact that you don’t have a visual designing tool means you literally cut & paste code, move it around, and wait for the preview to refresh and hope the result is what you expected, otherwise you just embed all of it in a VStack and try again while tweaking some .frame and .padding because the layout keeps breaking. Want to add a search field on top of that source list which doesn’t look like crap? Welcome to NSViewRepresentable and coordinators.
This doesn’t end here. I tried making a simple form. Something every app has for configuration or just CRUD UI. There is the Form element for doing this, which handles most elements beautifully by aligning the labels with the controls. But for some reason (iOS), the TextField label is used as a placeholder. So instead of the standard Label: TextField you get just TextField. And I found no way to override that. So it’s literally useless for any Mac app to use Form to layout a grid of labeled views properly. You don’t even have a grid view available, you just have to resort to HStack and VStack and that’s too little. Try aligning labels with controls sensibly.
I heard many other people are having problems with other advanced AppKit controls, such as NSTextView, NSTableView, NSOutlineView. Any non-trivial Mac application is bound to use one of these, so if you were to use them, you either wrap them in a representable + coordinator or go the traditional way and build with SwiftUI around it.
Despite all of this, I have no plans to abandon SwiftUI. I will use it where it’s suitable or if I can quickly get around its quirks, but I can’t see anyone building an entire Mac-assed application with it without lots of pain. Not today and perhaps not for a year or more. I do envision this is the future once SwiftUI is more consolidated and has more AppKit integrations.