At the WWDC in June 2019, Apple introduced – among other products, OSes and libraries – a new cross-platform UI framework named SwiftUI.
And I thought: WHAT?
I mean, who needs a new framework?
Cross-platform was of course the thing of the day. But I had expected Apple to focus on their marzipan framework, bringing more and more iPad apps to the Mac. Actually I thought that Apple might declare AppKit as deprecated and in turn add features to UIKit that would be needed on the Mac, making UIKit the framework of the future.
But I had never expected that they would start a new framework.
Especially like this! When I watched the presentation, I only saw the crippling of the InterfaceBuilder. InterfaceBuilder to me is by far the best UI editor I have ever worked with – and I’ve tried quite a lot. Especially because it does not create code but a resource file that can be used to create complete object trees at runtime.
And now that: a SwiftUI editor that creates code!
Okay, that code looked nice and clean, but still …
But when I tried out the new framework, I realized that I was totally wrong. Now, after some time working with the tools, I feel that Apple has done a great job!
So, let’s have a look.
What do you need for working with SwiftUI?
First of all: SwiftUI is still in beta. It requires a Mac with the beta version of macOS 10.15, aka “Catalina”. And you need the beta version of Xcode 11 as well. So go to developer.apple.com, get yourself a developer account if you don’t have one already, and sign up for the beta program.
Please be aware that macOS 10.15 is beta. You use it on your own risk! Some things don’t work quite right yet, but more important, some of the apps you want to work with might not even run on the new OS. So be warned!
Even SwiftUI is not error-free and probably not even complete yet. In fact, I have not been able to create a macOS app with SwiftUI. The skeleton program that Xcode creates simply does not run. But I expect these errors to be ironed out before autumn.
If everything is installed and working, we can go on.
How does SwiftUI relate to AppKit and UIKit?
Before we take a look at the framework and its editor, I want to talk a bit about the relationship between SwiftUI and AppKit / UIKit, these native frameworks for macOS and iOS respectively. Does SwiftUI replace them?
Not at all. It extends these frameworks.
When you take a look at the skeleton code that Xcode creates if you start a new project, you’ll find that the top most classes almost look the same as before. A scene or a window is created in their proper places. But then you’ll find these lines of code:
In the yellow lines you see the usage of some hosting components taking in an instance of a
ContentView. And with this
ContentView the SwiftUI part starts.
Any visual component you create with SwiftUI is embedded in a hosting component that in itself is a part of either the AppKit or the UIKit. I haven’t tried it out but I expect it to be the same with watchOS and tvOS where SwiftUI can also be used.
As a result, the applications you create are still native macOS, iOS, watchOS or tvOS apps along with their framework. But the major part of UI coding together with the app’s logic can be written in a way that can be ported or moved from platform to platform.
Enough talk, give me UI components!
Okay, this was a long introduction. But I wanted you to understand what you are working with.
Now, let’s take a look at this
ContentView. This is the first of your SwiftUI components. SwiftUI is centered on visual components that can be created and tested individually and combined to bigger components. All this is done in a declarative not an imperative way.
If you are a web developer doing React or Vue you will probably feel pretty much at home since the concepts have a lot in common.
When you select the
ContentView in the Project Navigator, you will see something like this:
The pane on the right side is called the canvas. It shows the current component, centered in the display of a simulated iPhone. Build and run – and your app will show exactly this display.
If the canvas does not show the component, you will probably find a button saying Resume. Click to resume the canvas.
If you click on the text component in the canvas, the corresponding code will be highlighted – and vice versa:
Now take a closer look at the code:
Two things are created: Firstly, a struct called
ContentView. That’s our view we can edit and use in our program.
Secondly, you see a struct called
ContentView_Previews. We will get to this one later. Please ignore it for the time being.
ContentView contains a variable named
body that returns
some View. The keyword
some is new to Swift 5.1 and means something like “an object that is a
View but I don’t care which one exactly.”
Let’s try and add a second line of text:
Type ⌘⇧+L to open the library. You see a list of components. Locate the
Text and drag it to the canvas below the word “Hello”.
The code changes to:
As a result, you get not only the new
Text component but also a
VStack that is grouping the two. That is needed because
body can only return one component. In this case, our
ContentView is a
VStack that contains two
You can edit the properties of the visual components either in the code editor or in the canvas. In any way, you will also find the Attributes Inspector ready to change its properties, like you would expect in any other UI editor.
If you want to add more components, you can select them from the library (⌘⇧+L).
The list of components is not too extensive, but it should be enough for most cases. There are the normal controls like text, button, or image as well as some container components like
The layout of the user interface is mostly done by combining different views in the two stack container types. By adding padding or offset, you can create nice layouts, very much like a web developer creates a UI using flex box.
Creating a new view
So far, we have only dealt with the
ContentView, the top level view that is put directly into the macOS Window or the iOS Scene. We could add a lot of components here, creating a complex dialog. But that is not very elegant. SwiftUI lets you create your own views that you can use within other views. Again, that’s like you do it in React or Vue.
To do that, hit ⌘+N to create a new file:
You’ll find a new template called SwiftUI View. Select it to create a new view. Name it ReminderView.
As an example, I want to create a component that represents a Reminder in some Todo-List app.
Change the code like this:
Your canvas shows the new view:
It displays a bordered representation of a simple reminder card. Remark that the image I used is for a non completed reminder. If you wand to show a completed one, change the image to
Image (systemName: "checkmark.circle").
But actually you would want the user to change the
completed state of a reminder, wouldn’t you? So let’s change the implementation and add some functionality:
Ok, what did we do?
First, we added a
Button. Interestingly, the
Button component just deals with the functionality not with its look. This is delegated to its child-components, in this case the
Images we already used.
I hope the code of the
action:-parameter is clear: It toggles the status of the
Of course we also need both images for both states. The
if-statement switches between the two representations.
Now what about this
@State? This annotation adds the needed functionality so that part of the view is automatically redrawn if the variable it depends on changes. It implicitly gives us some kind of reactive event-pattern functionality.
The view is nice to look at. But can we try out this code? Can we see our new component in action?
Yes, we can. Actually, it is quite simple to do. Just click on the “play” button in the lower right of the canvas just next to the base of the simulated iPhone:
It may take a while but after some time the design of the simulated iPhone changes: it gets its hardware buttons. This indicates that the canvas is now running and can be tested. Click on the image of the circle where we put the button to see the reaction.
Yes! Did you expect that? You cannot only see the results of your visual composition immediately, but can also try out the living code within a sandbox.
I think I have make that point clear: The canvas cannot only show the component and help editing its properties, it is also an interactive way to test and use the component.
As a web developer you might know Storybook, where you can try out components interactively. This is like having Storybook integrated within the IDE.
Configuring the sandbox
So far, we used fixed texts for the title and the description. But that’s not how our component normally would be used, is it? We rather want to pass the values as parameters.
Precautionary, we have declared our variables using
var and not
let. So we can inject concrete values at the point of creation. Now, let’s take a look at the bottom of the code and change it like that:
Here is the real magic of the new canvas of SwiftUI. The code between the
#if DEBUG and the
#endif – that will not be included in the shipping product – sets up the sandbox for our canvas. In this case, we can supply variables for our
The canvas changes and shows the new component with the new texts.
That was easy.
Okay, let’s do something weird: We want to see two different representations of our view at the same time. Change the sandbox again:
Now we have created a VStack with two ReminderViews each with different parameters. And our canvas looks like this:
Yes, we see both instances. Select the
Text that displays the reminder’s title in the code and both components will be highlighted:
Next, delete the template content for our
description, we don’t need them anymore. Of course, we have to declare the proper types now:
At that point, I got an error message like this in the canvas:
I had used the ReminderView in the
ContentView just for fun and forgotten about it. Now I received a compile error, because I had not supplied any init-parameters there. This error was easy to fix, I deleted the component from the
ContentView. Then a click on Try again – and my canvas was back online.
Properties for the views
In the last paragraphs, I have shown you how to work with the canvas. But I did not explain the code for the
ReminderView itself. I will catch up on that now.
Here’s the code again, followed by some explanations:
Spacer is an invisible component that stretches along the axis of the stack, taking all the remaining space. It is needed to stretch our
HStack to the maximum width.
You will see two different ways to passing parameters to components. First, some components I have given
HStack. Each component has its own list of parameters that can be passed to the
Other components have methods called on them, like
.font(.headline) on the title component.
These methods are actually some kind of properties as well. Most of them are generic and can be called on any component, like
.border. These methods all return the changed object again so that calls can be chained.
Some of these parameters can be manipulated interactively in the Inspector View, some others can be accessed via the library. Everything can be done in the code.
The SwiftUI framework together with the canvas tool are a great combination for developing user interfaces for Apple products across all platforms.
They follow a declarative and not imperative style where the state of an object is the truth and not its visual representation. You change the state and the state changes the UI. This is a different approach than the older model-view-controller pattern used in AppKit and UIKit.
The canvas tool directly shows the result of the code, without tedious edit-compile-run-cycles. Of course, under the hood these cycles take place, but as a developer you don’t need do worry about them. Everything is happening very quick.
The tool follows the principle of having an immediate connection between the code and the result. If you are more interested in this principle, I recommend the talks of Victor Bret e.g. “inventing on principle”.
By creating more than one instance of a component in the sandbox, you can visually design and test your components for different situations.
As I have said, SwiftUI is still beta. I hope Apple will iron out some errors and add some more functionality, but even now it looks and works great.
I would very much like to see tools like that for React or Vue, so that this great way of creating user interfaces does not stay limited to the Apple platform.
Apples developer documentation (incl. tutorials)
Hacking With Swift – Tutorial by Example