loading...
Cover image for SwiftUI first impressions / pain analysis

SwiftUI first impressions / pain analysis

hugh_jeremy profile image Hugh Jeremy ・3 min read

For years I've been occasionally dabbling in macOS native application development, and for years I've been resisting the urge to throw my MacBook out the window. Any delusions I've occasionally had about releasing native macOS apps have been flattened by the AppKit pain train.

Where's my Delegate? Or was it the Controller, Model, or View that I needed? Was it in my Storyboard? Xib? Nib? Jib? Why is Xcode crashing? What is this non-deterministic compiler error?

I can see how a dedicated developer could become a weapon with AppKit, but if you're multi-disciplinary the time input/reward ratio is just way off.

Apple has presumably realised this, hence the new kid on the block: SwiftUI. I'd heard about this new-fangled "SwiftUI". It was only this week that my urge to self-flaggellate was strong enough to try it. So I fired up Xcode, and...

Well. What a pleasant surprise. Everything, and I mean the whole damn production, is boiled down into one glorious concept: The View.

This rustles my jimmies in all the right directions. The only way I ever made any progress with AppKit was to ignore its psychotic smorgasbord of concepts and build self-contained NSView subclasses. Then, those subclasses could be composed into a UI.

That's effectively SwiftUI in a nutshell. You create View implementations, and then you add them to each other. That's it.

View is a protocol, not a class. No inheritance. You have full flexibility to initialise this bad boy however the hell you want. They're just fresh-off-the-stack structs with a .body property requirement.

Could it get better? Yes it could get better. Some people are imperative people. The want to tell you how to do something, rather than what they want done. These people have titles like "[insert JavaScript framework] Evangelist" and you should socially distance yourself from these people.

Better people are declarative people. They tell you what the objective is, and then leave you alone to achieve it. SwiftUI is a declarative person. The difference in code:

# Imperative Python
relevant_heights: List[int] = list()
for tree in forest:
    if tree.age == 4:
        relevant_heights.append(tree.height)
return sum(relevant_heights)

# Declarative Python
return sum([t.height for t in forest if t.age == 4])

In the first example, we told Python how to find the right tree heights. In the second example, we told Python what we wanted and let it work out the implementation details itself.

If you've ever worked in SQL, you will be familiar with the declarative style, because SQL is entirely declarative:

/* Declarative SQL */
select sum(height)
from   trees
where  age == 4

The declarative attitude is the one required to grok the following:

struct Header: View {

    var body: some View {
        VStack {
            Text("Top row text")
            Text("Bottom row text")
        }    
    }
}

We declare that we would like a vertical stack of views (VStack), inside of which we would like two pieces of text (Text).

Alt Text

When I first saw this, I was frustrated. Where exactly do we return from inside the VStack? And what is returned? How can two Text declarations magically turn into two lines of text?

Being an absolute SQL fanatic, I found peace by accepting that we are declaring what we want rather than how we want it done. Writing Swift code against the SwiftUI API is more like writing SQL than say, imperative AppKit code.

We can mix and match views willy-nilly. Say we declare an H1 view, which in our application will be roughly analogous to <h1> in HTML:

struct H1: View {

    let headingText: String

    var body: some View {
        Text(headingText).font(
            .system(
                size: 32,
                weight: .bold,
                design: .default
            )
        )
    }
}

We can now use H1 inside our earlier Header example:

struct Header: View {

    var body: some View {
        VStack {
            H1(headingText: "Top row text")
            Text("Bottom row text")
        }    
    }
}

Producing:

Alt Text

That really is it, kids. Everything else is a variation on the them of defining View implementations and composing them together. Nested hierarchies of View become your application user interface.

What a pleasant surprise. SwiftUI might be a keeper. Some quick summary thoughts:

Good

  • Everything above
  • Xcode doesn't crash constantly anymore
  • Swift package manager is great now

The Bad

  • Not many built in controls, re-using AppKit classes (e.g. NSTableView) quickly becomes necessary
  • AppKit / SwiftUI interaction is poorly documented
  • All the Apple docs are (surprise) focused on UIKit people, & iPhone GUI paradigms

Want to dive a little deeper? In a follow up, I discuss how to integrate an AppKit NSTableView into a SwiftUI View hierarchy.

Posted on by:

hugh_jeremy profile

Hugh Jeremy

@hugh_jeremy

I build systems to solve difficult problems. CTO Procuret, rural networking specialist, general purpose Uber-nerd.

Discussion

pic
Editor guide