In simple terms, we tell SwiftUI how we want our user interface (UI) to look and work, and it further organizes all user interactions.
What is SwiftUI?
SwiftUI is a collection of UI building tools that allows us to design applications declaratively. In simple terms, we tell SwiftUI how we want our user interface (UI) to look and work, and it further organizes all user interactions.
The declarative UI is best understood compared to the imperative one that iOS developers did before iOS 13. In an imperative user interface, we could force a function to be called when a button is pressed, and inside a function, we would read a value and change the line on the screen depending on what is happening.
Imperative UI causes all sorts of problems, most of which have to do with the state, which is another fancy term for “the value we store in our code.” We need to keep track of what state our application is in and make sure that each time our UI reflects that state correctly.
If we have one screen with one boolean property that affects the user interface, we have two states: the boolean value can be turned on or off. If we have two booleans, A and B, we now have four states:
A is off, B is off
A is on, B is off
A is off, B is on
A is on, B is on
What if we have three booleans? Or five? Or integers, strings, dates, etc.? Well, then things get much more complicated.
If you’ve ever used an app that says you have one unread message, no matter how many times you tried to read it, it’s a state issue – i.e., it’s an imperative UI issue.
A declarative user interface allows us to tell iOS about all possible states of our application at once. We can say that if we are logged in, then we need to show a welcome message, but if we are logged out, show the login button instead. We don’t need to write code to navigate between these two states manually – it seems like a strange way of working now!
Instead, we can let SwiftUI navigate between UI layouts when state changes. We’ve already said what to show based on whether the user is logged in or not, so when we change the authentication state, SwiftUI can update the UI on our behalf.
This is what declarativeness means: we do not force SwiftUI to show or hide components manually, we just tell it all the rules we want it to follow and leave it running so it can enforce those rules itself.
But SwiftUI doesn’t stop there: it also acts as a cross-platform user interface that works across iOS, macOS, tvOS, and even watchOS. This means that you can now learn one language and create one layout and then deploy it wherever you like.
SwiftUI or Interface Builder?
Every iOS developer is familiar with Interface Builder and storyboards, and possibly the XIB as well. You may not like them, but everyone is familiar with them. If you haven’t used them before, just skip this part. Most likely you haven’t manually edited the XIB. Well, except maybe once, but in general the answer is most likely no – XIBs contain a fairly large amount of XML, which is not easy to read and difficult to edit.
To make things worse, storyboards get bigger and bigger over time. They can start small, of course, but then you add another view controller and one more and one more, and suddenly you realize that you have ten screens in one file and any source control changes you make are suddenly quite painful. This is just part of the problem – it’s almost impossible to figure out what has changed when someone opens a pull request to receive changes in screens. There is another problem with storyboards and XIBs.
As you see, Interface Builder knows little about our Swift code, and our Swift code knows little about Interface Builder. As a result, we get a lot of unsafe situations: we hold Ctrl and drag elements from Interface Builder into our code to associate something with an action, but if we then remove this action, the code will still compile – Interface Builder doesn’t really care if the code does not exist anymore.
Likewise, when we create a View Controller in a storyboard or define table view cells in a queue, we use strings to identify important objects in our code – the system is so ubiquitous that it even has its own name: “Stringly-typed API”. Even so, we need to use the casting because Swift cannot know that the resulting table view cell is actually a TableViewCell.
These problems exist because Interface Builder and Swift are very different things. This is not surprising – Interface Builder not only appeared before the original Mac OS X existed but was also designed in many ways to resemble the way Objective-C works.
SwiftUI takes a major step forward. It is a Swift-only framework, not because Apple decided it was time for Objective-C to die, but because it allows SwiftUI to leverage the full range of Swift functionality – value types, opaque return types, protocol extensions, and more.
SwiftUI allows solving many of the problems that iOS developers faced with the older Swift + Interface Builder approach:
- We no longer have to argue about the software or storyboard design because SwiftUI provides us with both at the same time.
- We no longer need to worry about version control issues when working with the user interface, because the code is much easier to read and manage than XML files.
- We no longer need to worry so much about stringly-typed APIs – they still exist, but there are significantly fewer of them.
- We no longer need to worry about calling non-existent functions because our UI is checked by the Swift compiler.
So, we hope you agree that there are many benefits to switching to SwiftUI! What’s your take on this?
Stay tuned with Software Focus!