0% found this document useful (0 votes)
40 views

SwiftUI - A New Beginning - Asynchronous Programming With SwiftUI and Combine - Functional Programming To Build UIs On Apple Platforms

Uploaded by

idontcare
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
40 views

SwiftUI - A New Beginning - Asynchronous Programming With SwiftUI and Combine - Functional Programming To Build UIs On Apple Platforms

Uploaded by

idontcare
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 18

© The Author(s), under exclusive license to APress Media, LLC, part of Springer Nature 2023

P. Friese, Asynchronous Programming with SwiftUI and Combine


https://doi.org/10.1007/978-1-4842-8572-5_1

1. SwiftUI: A New Beginning


Peter Friese1
(1) Hamburg, Germany
Every year at the Worldwide Developers Conference (WWDC), Apple introduces new features and capa‐
bilities to their platforms and operating systems. The event is met with great anticipation, as it means de‐
velopers will finally be able to get their hands on the new APIs and frameworks Apple engineers have
been working on for the past year, and incorporate them into their own apps.

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.

—Steve Jobs, 2007

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.

Why a New UI Framework?


Why implement a new UI toolkit, if there are already UIKit and AppKit, you might ask, and you’d be for‐
given for doing so. After all, implementing a UI toolkit is no small feat, much less bringing it to production
quality, shipping it, and asking an entire community of app developers to adopt it.

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.

Declarative vs. Imperative


Traditionally, there have been two main ways how developers build UIs:

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.

Composition over Inheritance

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

Everything Is a View—Except That It Isn’t

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.

UIs Are a Function of Their State

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.

In SwiftUI, the UI is a function of the model’s state

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.

A Quick Tour of SwiftUI

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.

By following this little tutorial, you will learn how to

– Create a new SwiftUI project in Xcode


– Use the code editor and the Attributes inspector to make two-way changes to the UI
– Use SwiftUI’s simple state management capabilities to ensure UI and model are kept in sync

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

Creating a New SwiftUI App

1.Launch Xcode and click Create a new Xcode project.

Figure 1-1 Creating a new project in Xcode

2.Make sure to select the iOS section, and then choose the App template.

Figure 1-2 Choosing the iOS App template


3.Provide a name for your project (I chose Hello SwiftUI), and make sure the following options are set:
1.
– Interface: SwiftUI
2.
– Life Cycle: SwiftUI App
3.
– Language: Swift

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:

Figure 1-5 Xcode source editor and preview canvas

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.

Let’s now change how the text looks:

– 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

Let’s make one more change before we move on:

– In the source code editor, Command + Click the Text view.


– In the pop-up, choose Show SwiftUI Inspector.
– Xcode will display the inspector in a pop-up window.
– Change the font from Inherited to Title.
– Observe how Xcode updates the source code and the preview simultaneously.

Figure 1-8 Updating the font using the SwiftUI Inspector


Congrats, you have just experienced Xcode’s two-way editing tools for SwiftUI! Note that you can use any
of them at any time. The SwiftUI Inspector is a great tool for exploring the attributes and capabilities of
SwiftUI’s views. Once you get more acquainted with the individual SwiftUI views, you might find it more
efficient to use the source code editor and its code completion to modify the views directly.

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.

Adding Some Interaction to Your App

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.

Figure 1-9 Making the elements on the canvas selectable

– 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:

struct ContentView: View {


var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, Peter!")
.font(.title)
.foregroundColor(Color.pink)
Button("Button") {
Action
}
}
.padding()
}
}

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:

struct ContentView: View {


var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, Peter!")
.font(.title)
.foregroundColor(Color.pink)
Button("Tap me") {
print("Hello")
}
}
.padding()
}
}
}

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.

Here is the UI we want to achieve.


Figure 1-13 Automatically updating greeting

Let’s first update the existing UI:

– 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).

Figure 1-14 Filtering the list of views

– Drag the Text Field view into the preview canvas, right above the label which reads Hello, Peter!.

The ContentView source code should now look like this:

struct ContentView: View {


var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
TextField("Placeholder", text: Value)
Text("Hello, Peter!")
}
.padding()
}
}
Again, Placeholder and Value are highlighted to indicate these are just editor placeholders:

– Replace the “Placeholder” text with "Enter your name here".


– Just above the line starting with var body, insert the following text: @State var name = "". This will
define an empty instance variable named name and tell SwiftUI to handle its state for you13.
– Replace the Value editor placeholder with $name—this will tell SwiftUI to bind the name variable to the
TextField. Whenever the user enters some text, the value of the name variable will be updated. Vice
versa, if the value of the variable is changed, SwiftUI will update the TextField instance and display the
updated value. You have now essentially set up a two-way binding14.
– Change the content of the Text view to "Hello, \(name)!". This is called string interpolation—Swift
will replace \(name) with the current value of the name variable.

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.

Your code should now look like this:15

struct ContentView: View {


@State var name = ""
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
TextField("Enter your name here", text:$name)
.padding(.all)
.border(Color.pink, width: 1)
.padding(.all)
Text("Hello, \(name)!")
.font(.title)
.foregroundColor(Color.pink)
}
.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

– Add a button to reset the name variable to an empty string.


– When the name variable is empty, the greeting will read Hello, !, which looks a bit awkward. Using
what you’ve learned in this chapter, can you try to think of a way to only show the comma if name con‐
tains at least one letter?

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

2 WWDC 2019 Keynote—https://youtu.be/psL_5RIBqnY?t=7782

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

14 Again, this is something we’ll be covering 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.

You might also like