SwiftUI - A New Beginning - Asynchronous Programming With SwiftUI and Combine - Functional Programming To Build UIs On Apple Platforms
SwiftUI - A New Beginning - Asynchronous Programming With SwiftUI and Combine - Functional Programming To Build UIs On Apple Platforms
To enable developers to make use of the new features, Apple provides new APIs, SDKs to use them, and
often new tooling, such as Xcode.
While all those new features Apple has launched at WWDC throughout the years have been exciting and often
breathtaking, sometimes they ship an update of extraordinary significance.
Every once in a while, a revolutionary product comes along that changes everything.
Obviously, the unveiling of the original iPhone in 2007 was such a moment.
The release of the Swift programming language in 2014 was another moment of significance. Swift made
software development much easier and a lot more approachable for developers who might have been
scared away by Objective-C and its rather special syntax and Smalltalk-esque call semantics. It’s no exag‐
geration to say that Swift and Swift Playgrounds brought more developers to Apple’s platforms than ever
before. Swift Playgrounds—an interactive programming environment geared toward explorative and
playful interaction with Swift—has positioned Swift as a great language for anyone who is looking for a
low-barrier way to explore and learn programming. Swift and Swift Playgrounds have democratized soft‐
ware development. And the results of this bold move are visible each year at WWDC, when Tim Cook
takes the stage to announce how many apps are on the App Store and which percentage of those use
Swift. At WWDC 2021, Susan Prescott (VP of Developer Relations) unveiled that “the majority of the top
1000 apps on the App Store are built using Swift.”1
The release of SwiftUI in 2019 was another such moment. When Josh Shaffer stepped out onto the stage
to announce SwiftUI,2 people were stunned by its ease of use and the speed at which it was possible to
build UIs from scratch. But also, and maybe even more importantly, people were thrilled by the fact that
SwiftUI included a native way to manage application state—something notoriously complicated. Apple
even went so far as to implement their own version of RxSwift: Combine—a functional reactive frame‐
work centered around the idea that applications can be seen as a piece of software that transforms
events over time.
To better understand what all of this means and why exactly Apple chose to implement a new UI toolkit,
let’s dive a little deeper.
Here are some of the driving factors that might have influenced Apple’s decision.
First and foremost, we have to acknowledge that Apple positions SwiftUI as a cross-platform UI toolkit.
The introduction on the SwiftUI landing page3 specifically mentions that “SwiftUI helps you build great
looking apps across all Apple platforms with the power of Swift — and surprisingly little code. You can bring
even better experiences to everyone, on any Apple device, using just one set of tools and APIs.” Apple now
has no less than five consumer-facing platforms (iOS, iPadOS, watchOS, tvOS, and macOS), and as anyone
who has tried to ensure feature parity across platforms will be able to tell you, supporting more than just
one platform is becoming increasingly burdensome for developers. By providing a unified way to reason
about and build UIs for as many of these platforms as possible, Apple is relieving developers of this bur‐
den. It should be noted, however, that SwiftUI is not trying to fit a “write once, run everywhere” par‐
adigm—on the contrary, it does have platform-specific parts. But it’s much easier to learn one UI toolkit
and use it across all those platforms than having to learn a new paradigm for each individual platform.
Secondly, SwiftUI aligns with Apple’s investment in helping developers to write better software and reduce the number
of potential bugs in the apps on the App Store. Apps with fewer bugs tend to get better ratings on the App Store—and
consequently return a higher revenue. The Swift language contains many features that make it easier to write bug-free
software. Its language designers and compiler engineers have been working hard on eliminating potential causes for bugs,
such as
– Null dereferencing
– Type mismatches
– Incomplete decision trees
– …and more
SwiftUI has two major attributes that help increase software quality:
1.It has built-in state management, an aspect of UI development that is notoriously challenging.
SwiftUI’s state management makes it easier to build UIs that reflect the state of the app at all times—
even across multiple screens.
2.It is centered around a domain-specific language (DSL4) that makes it easier to describe the UI, elimi‐
nating any issues that might be caused by incorrectly instantiating and structuring UIs, and making
it easier to write and reason about UIs.
And lastly, SwiftUI makes software development more approachable. It is not without reason that we’ve
seen a lot more web developers and designers start building UIs in SwiftUI. Putting together a working
prototype in SwiftUI has become increasingly feasible and has helped to improve the collaboration be‐
tween UI designers and developers. Xcode’s preview canvas for SwiftUI has dramatically shortened turn‐
around times and provides developers and designers with instant feedback to the changes they make.
This instant feedback has enabled more students and beginners to get started with app development and
achieving results within minutes rather than hours or even days.
SwiftUI Principles
Before we take the first steps in SwiftUI, it is worth taking a look at some of its key properties.
1.Using visual tools (such as Interface Builder) to lay out the UI elements, and then connecting their
app’s code to the UI elements
2.Programmatically laying out the UI elements
In the past couple of years, there has been an increasing number of UI toolkits that follow a declarative
approach to building UIs. These toolkits make use of so-called internal or external domain-specific lan‐
guages (DSLs) to let developers specify the structure of the UI. Examples for such toolkits are Angular5,
React6 and JetPack Compose7.
In an imperative world, you need to implement everything yourself: layout, behavior, data binding. In
contrast, a declarative approach allows you to simply tell the framework what to do, and it will take care
of the specifics for you. It’s a bit like cooking a meal by yourself (imperative) or going to a restaurant,
where you place your order and receive a nicely cooked meal in return (declarative).
State Management
Managing state is one of the major challenges when writing an application. It’s quite simple when your
app only has one screen, but as the number of screens increases, so does the complexity of keeping all
parts of the UI and the underlying data model in sync.
It becomes even more of a challenge in apps that share data with a backend and synchronize data via the
Internet. Not to mention the challenges you will face when writing a multiuser app that needs to ensure
the data is up to date and in sync for all users who simultaneously work on the same piece of data (e.g., a
shared document in Google Docs, or a task lists in a to-do list application).
Probably all of us have used an app that, despite the fact you updated your address in a detail dialog,
didn’t reflect that change of address in the shopping basket. Excruciating!
Data binding is not an entirely new concept on Apple’s platforms—Cocoa Bindings8 on macOS has been
around for a number of years now, providing developers with the basic tools to map data between UI ele‐
ments and the underlying data model. Despite developers clamoring for a data-binding framework for
iOS, Apple never provided one—so far. Left to their own devices, developers had to come up with their
own, homegrown solutions, and it didn’t take long for the community to come up with iOS-specific imple‐
mentations of functional reactive frameworks such as RxSwift9 or ReactiveSwift10.
With SwiftUI, Apple finally acknowledged the need for a native framework for keeping your data model
and UI in sync. SwiftUI comes with a number of tools to help you build UIs that reflect the state of your
model at all times, and keep in sync across your entire app.
Most importantly, SwiftUI combines well with Combine, Apple’s own implementation of a reactive frame‐
work, making it possible to express the flow of data in your apps as a stream of events over time that are
transformed by business rules and logic operators to meet the requirements of the app.
In contrast to UIKit and many other UI frameworks, SwiftUI encourages developers to compose their UIs
by piecing together many small UI components. Developers who come to SwiftUI from UIKit will find this
rather surprising, as they’ve learned to minimize the number of UI elements—in particular in scrolling
views such as UITableView or UICollectionView to optimize their app’s performance.
The reason for this is that SwiftUI is a DSL that describes the look of a UI, rather than prescribing the UI
primitives it is made up of. The SwiftUI team has encouraged developers to make liberal use of views to
compose their UIs right from the onset—in their first-ever public presentation of SwiftUI on the WWDC
2019 stage, Jacob Xiao, SwiftUI Engineer, says “and with SwiftUI, views are really lightweight so you don’t
have to worry about creating extra views to better encapsulate or separate your logic.”11
Once you start building UIs in SwiftUI, you will quickly notice that all the UI elements are called Views—
even a screen is considered a View! It is tempting to think that all those views are equivalent to UIView
(or the respective subclass). SwiftUI might in fact choose to render some parts of your UI using one of
UIView’s subclasses. However, it is worth noting that when SwiftUI talks about Views, it doesn’t refer to
the specific instances of a UI element on the screen, but rather a description of that element.
In fact, it might have been easier if the SwiftUI team had decided to say “everything is a view
description”—but of course, that’s not as catchy.
One of the biggest challenges in building UIs is making sure the UI reflects the state of the underlying
data model at all times. Previously, developers had to use a variety of tools and mechanisms to ensure
any changes to the model are reflected in the UI, and vice versa. A variety of architectural patterns for
dealing with this challenge have been devised: MVC (Model View Controller), MVVM (Model, View,
ViewModel), MVP (Model View Presenter), VIPER (View, Interactor, Presenter, Entity, and Routing), etc.
With SwiftUI, Apple decided to bake state management right into the framework. In SwiftUI, the UI is a
function of the model’s state. This is worth keeping in mind.
To update the UI, you no longer directly manipulate the individual UI components. Instead, you bind the
UI elements to underlying models. Every time you change an attribute on the model, SwiftUI will refresh
the UI elements that are bound to this attribute, making sure the UI and model are always in sync.
This also means it becomes very difficult to accidentally forget to update parts of the UI: all parts of the UI
that are bound to an underlying model will be updated automatically by SwiftUI for you.
To get a better understanding of SwiftUI and how it works, let’s build the traditional “Hello World” sam‐
ple application. But instead of just displaying “Hello World,” we will use SwiftUI’s built-in state manage‐
ment capabilities to greet you by name.
Prerequisites
To follow this tutorial (and all others in this book), you will need the following:
– A recent version of Xcode (14 or higher)
– A Mac running macOS Monterey
2.Make sure to select the iOS section, and then choose the App template.
Figure 1-3 Setting the project name and other project options
For now, you can leave the Include Tests option unchecked.
4.Click Next and choose where to store your project. You can leave the Create Git repository on my Mac option checked,
or turn it off if you like.
Figure 1-4 Choosing a folder to save the project to
Xcode will create the project for you, and you should find yourself in the editor for ContentView.swift:
To the right of the editor, you will find the Canvas, which will display a preview of your UI. If it shows a message saying
“Preview paused”, click the Resume button or press Option + Command + P. After a short moment, you will see a
preview of your UI:
Figure 1-6 Xcode editor and UI preview
Let’s make a few changes to get a feeling for SwiftUI’s two-way tooling:
– In the code editor, update the text of the greeting so it says your name instead of world. So for me,
"Hello, world!" becomes "Hello Peter!".
– Observe how the preview is updated immediately with every single keystroke you make—without re‐
quiring you to compile and relaunch the app on your phone or Simulator.
– Make sure the cursor is still on line 16 (the line that says Text("Hello, (your name)").
– In the Attributes inspector (on the right-hand side of the Xcode window), open the Color drop-down
menu and choose a different color.
– Observe how, as you make changes, Xcode immediately reflects this change in both the preview canvas and the code edi‐
tor.
Figure 1-7 The updated text color is reflected in the editor as well as the preview canvas
The modifications you’ve applied to the Text view are called View Modifiers, and we’ll talk about them in
more depth in Chapter 3.
Let’s add some interactivity to your app—and learn how to use the Xcode Library along the way!
– Make sure you’re still in the source code editor and that the preview pane is still visible.
– Make the elements in the canvas selectable by clicking on the small icon with a mouse pointer on it.
– Click the + icon in the Xcode toolbar (right above the preview pane), or hit Command+Shift+L to open
the Library window.
– Make sure the Views library is selected (the leftmost icon).
Figure 1-10 The Views library
– Find the Button view and drag it out of the library and into the preview canvas, right below the Hello,
(your name) text.
– Notice how Xcode will highlight the drop location as you drag the button view around on the preview
canvas.
Figure 1-11 Dragging a button underneath the text view on the preview canvas
Once you drop the Button into the code editor, Xcode will automatically update the source—it should now look like this:
Notice how both Action and Content are colored slightly different—this indicates these two pieces of text are an
editor placeholder. You can navigate between those placeholders by pressing the Tab key on your keyboard.
– Click the Action placeholder and press Enter to replace it with the following text: { print("Hello")
}.
– Click the Content placeholder (or press the Tab key), and replace it with the following text: Text("Tap
me").
The source code of your ContentView should now look like this:
To see the result of your work so far in action, we need to run the app on the Simulator:12
– Drop down the Destination menu in the Xcode toolbar (or press CTRL + Shift + 0), and select one of the
iOS Simulators.
– Click the Run button (or press CMD+R).
– Open the Debug Console (View ➤ Debug Area ➤ Activate Console, or press the Command+Shift+C keys.
– Once the app has started up in the Simulator, tap the Tap me button.
– You should see the text “Hello” appear in the debug output.
Figure 1-12 The app running on the Simulator, with some output in the Debug Console
Using SwiftUI’s State Management to Keep UI and Model in Sync
To whet your appetite for more SwiftUI, as a final step in this chapter, let’s make use of SwiftUI’s state
management to update the greeting whenever the user enters their name.
– Remove the Button from the source code—we don’t need it anymore, as we’ll be updating the UI
whenever the user enters a text.
– Open the Library (using either the + button or by pressing Command+Shift+L).
– Find the Text Field view (by typing Text into the library’s search field).
– Drag the Text Field view into the preview canvas, right above the label which reads Hello, Peter!.
To make the input field a bit more pleasing to the eye, let’s add some padding and a border:
– Make sure the TextField is selected by placing the cursor somewhere within the line starting with
TextField.
– In the SwiftUI Inspector, click into the small circle at the right edge of the Padding section. This will
add some padding around the text field.
– At the bottom of the SwiftUI Inspector, place the cursor within the input field labelled Add Modifier.
– Type border, and then click the Border drop-down menu item to add a border to your TextField. You
can choose a color of your liking.
– Finally, add some padding around the border by typing padding into the Add Modifier field once more.
Click the Padding drop-down menu item to insert the padding.
To see your code in action, click the Live button on the bottom toolbar of the preview canvas. After a short moment, you
can start interacting with the live preview. Try typing your name and observe how the greeting is updated instantaneously
with every single keystroke.
Figure 1-15 Running the app in live preview
To run the app on the iOS Simulator or a physical device, choose the device in the run destination drop‐
down in Xcode’s title bar, and then press the Run button.
Congratulations! You’ve just implemented your first SwiftUI application driven by SwiftUI’s powerful
state management.
Exercises
Summary
In this chapter, we looked at some of SwiftUI’s specific properties and why Apple launched a completely
new UI toolkit in the first place. We learned what the differences are between declarative vs. imperative
UI frameworks, that SwiftUI favors composition over inheritance, and that everything is a view. We
talked about SwiftUI’s state management, and how this is the basis for SwiftUI’s premise that the UI is a
function of an app’s state.
Next, you experienced first-hand how easy it is to build a SwiftUI application. You learned how to use
Xcode’s two-way tooling for building SwiftUI user interfaces, and started to develop an understanding of
when to use the graphical tools, and when the source code editor might be more efficient.
Finally, you dipped your toes into using SwiftUI’s state management, which hopefully got you excited
about how much easier this is than having to wire up UI updates manually.
With this under your belt, it is now time to take a closer look at SwiftUI and some of its key UI elements.
Footnotes
1 WWDC 2021 Keynote—https://youtu.be/0TD96VTf0Xs?t=5800
3 https://developer.apple.com/xcode/swiftui/
4 Specifically, a so-called internal DSL. See DSL Engineering: Designing, Implementing and Using Domain-Specific
Languages by Markus Voelter to learn more about DSLs.
5 https://angular.io/guide/glossary#domain-specific-language-dsl
6 https://reactjs.org/
7 https://developer.android.com/jetpack/compose
8 https://bit.ly/3PBVoOZ
9 https://github.com/ReactiveX/RxSwift
10 https://github.com/ReactiveCocoa/ReactiveSwift
11 WWDC 2019 Session 204, Introducing SwiftUI: Building Your First App, time code 11:56 (https://bit.ly/3F‐
Saz3k)
12 In previous versions of Xcode, it used to be possible to run the application in Live Preview in order to see the de‐
bug output. This is no longer possible, as this feature has been turned off by Apple in Xcode 13:
https://bit.ly/3hmRKMc
13 Don’t worry if you’re not familiar with @State—we will be discussing in Chapter 4
15 You might see some of the values you just inserted be highlighted. This means they’re placeholders. If that’s the
case, click on the placeholders and then press the Enter key to commit the value. You can use the Tab key to cycle
through all the placeholders in your file.