A Year of SwiftUI

At WWDC 2019 (that’s last year), Apple introduced an amazing new UI framework - SwiftUI. Its introduction was (for me at least) on par with the announcement of Swift itself. I’d like to take you through my adventure with SwiftUI - version 1 - to show what you’ve missed and to hopefully, prepare you for Swift 2.0

Reactions

I had recently been working with React Native and was planning to re-write the app for iOS. This was well after WWDC 2019, so I had already heard of SwiftUI. My work with React Native was important in that I was already in the “reactive” frame of mind. That is, I worked with a UI whose display was state driven and bound tightly with the state. If you aren’t familiar with reactive programming here is a quick snapshot:

Your UI is composed of controls whose content (or appearance) is tied to a value in the component’s state. For example, a label whose’s text property is the value of state.amount. Whenever you change amount in the state, the UI automatically refreshes with the updated value. In other words, you do not programmatically assign the label an updated value; instead, the label draws its value from the state. Or, the UI reacts to changes in the state. Clever, huh?

Having been thinking along those lines, I started looking into SwiftUI. Imagine my surprise at seeing @State and talk about the UI reacting to changes in the state. Apple had gone done their own version of reactive programming! And it wasn’t just a little nod toward it - it was full-fledged deep end.

SwiftUI is only part of the new offering. Along with updates to Swift itself (which are crucial to making SwiftUI syntax so easy) is the Combine framework. Combine is what allows @State to work and enables the Observer pattern to be so easily incorporated into your apps.

So this was going to be the new way forward to develop iOS apps. OK, that’s what I was going to do with this React Native re-written app: SwiftUI 100%.

There were a lot of bumps and challenges along the way. And you can read challenges as hair-pulling and doubt as to whether this was the right decision or not.

First off, I knew SwiftUI did not fully replace UIKit. I knew I had to write integration code - Apple’s own tutorials to get you started with SwiftUI did that. For example, the app would need to use MapKit and MKMapView was not a SwiftUI element. Fortunately Apple was prepared for this and provided a way to wrap UIKit components so that they would appear to be SwiftUI elements. Pretty neat actually.

Secondly, I had to really look at problems differently. How do I set up the UI and its state so that when values change the right parts of the UI change? How do I receive new values from the remote service and get the UI to reflect those new values? How I put up a date chooser? How can I make scrolling through a 2000 element list faster? The challenges just kept coming.

A Model Year

You may be familiar with the “massive view controller” problem. This is where you pack everything and the kitchen sink into a single UIViewController file. You put access to your data, manipulations for that data, formatting that data, etc. all into the file whose real job is to get the UIView to display. It is easy to fall prey to this, especially as you are flushing out ideas or doing prototyping.

And this exactly what I started do with SwiftUI. I wasn’t concerned at first with separation of concerns - I was more interested in understanding how SwiftUI worked. But in forgoing this design pattern, I actually missed a key part of how SwiftUI works. What happened was that I was trying to get the screen to see changes the code was making, but they weren’t showing up.

I took a step back and realized that I was neglecting a very powerful concept in SwiftUI - the model. It’s pretty simple: you put your data into a class that has functions to manipulate it and then make the UI observe changes to it.

SwiftUI provides ObservableObject for this purpose; it’s part of Combine. When you make a class Observable, you can select properties to be @Published which sets up the observer pattern and all the code needed to watch for changes.

I pulled a lot of code out the UI classes and into models. I wound up with lots of models - essentially one per “screen” with some go-betweens. This allowed me to just set up the binding between the UI and the data in the model, have code - like remote server call handlers - update the appropriate models which would then automatically trigger the UI to change. Voila - an app!

Summary

As often as I questioned my decision to use SwiftUI, I just as often determined it was the right path. Apple was going to make this its de facto way to write apps. If you wanted to be in the lead position and wanted to take advantage any new stuff, you needed to be with SwiftUI.

And look what happed at WWDC 2020: Widgets and App Clips. You write those in SwiftUI. And - maybe even more important - cross device deployment. Your app can run on an Apple Watch, iPhone, iPad, Apple TV, and macOS - one app. SwiftUI’s runtime makes sure your app looks the best for the device and behaves appropriately. I’m sure there’s some tweaking you do in the app to actually make that happen, but Apple’s done all the heavy lifting for you - IF you use SwiftUI.

A lot of folks have been afraid to take the plunge, citing the old “SwiftUI is 1.0 and will change or is buggy.” Yeah that was true. So now you’ve got SwiftUI 2.0 on the horizon - do you want to be a leader or do you want to hang back and eat dust?

Previous
Previous

GIT Merge & Squash

Next
Next

Collapsable Section Headers in SwiftUI