Chapter 3
Build Your First App in Swift and SwiftUI

Learn by doing. Theory is nice but nothing replaces actual experience.

– Tony Hsieh

By now you should have installed Xcode and some understanding of Swift. If you have skipped the first two chapters, please stop here and go back to read them. You need to have Xcode installed in order to work on all exercises in this book.

In the previous chapter, you have tried out to create some UI components with SwiftUI. In this chapter, we will dive a little bit deeper and give you a proper introduction of the SwiftUI framework. On top of that, you will have an opportunity to create your first iOS app.

An Introduction to SwiftUI

In WWDC 2019, Apple surprised every developer by announcing a completely new framework called SwiftUI. It doesn't just change the way you develop iOS apps. This is the biggest shift in the Apple developer's ecosystem (including iPadOS, macOS, tvOS, and watchOS) since the debut of Swift.

SwiftUI is an innovative, exceptionally simple way to build user interfaces across all Apple platforms with the power of Swift. Build user interfaces for any Apple device using just one set of tools and APIs.

- Apple (https://developer.apple.com/xcode/swiftui/)

Developers have been debating for a long time whether we should visually design the app UI or write the UI in code. The introduction of SwiftUI is Apple's answer. With this brand new framework, Apple offers developers a new way to create user interfaces. Take a look at the figure below and have a glance at the code.

Figure 3-1. Programming in SwiftUI
Figure 3-1. Programming in SwiftUI

With the release of SwiftUI, you can now develop the app's UI with a declarative Swift syntax. What that means to you is that the UI code is easier and more natural to write. Compared with the existing UI frameworks like UIKit, you can create the same UI with way less code.

Declarative vs Imperative Programming

Like Java, C++, PHP, and C#, Swift is an imperative programming language. SwiftUI, however, is proudly claimed as a declarative UI framework that lets developers create UI in a declarative way. What does the term "declarative" mean? How does it differ from imperative programming? Most importantly, how does this change affect the way you code?

If you are new to programming, you probably don't need to care about the difference because everything is new to you. However, if you have some experience in Object-oriented programming or have developed with UIKit before, this paradigm shift affects how you think about building user interfaces. You may need to unlearn some old concepts and relearn new ones.

So, what's the difference between imperative and declarative programming? If you go to Wikipedia and search for the terms, you will find these definitions:

In computer science, imperative programming is a programming paradigm that uses statements that change a program's state. In much the same way that the imperative mood in natural languages expresses commands, an imperative program consists of commands for the computer to perform.

In computer science, declarative programming is a programming paradigm—a style of building the structure and elements of computer programs—that expresses the logic of a computation without describing its control flow.

It's pretty hard to understand the actual difference if you haven't studied Computer Science. Let me explain the difference this way.

Instead of focusing on programming, let's talk about cooking a pizza (or any dishes you like). Let’s assume you are instructing someone else (a helper) to prepare the pizza, you can either do it imperatively or declaratively. To cook the pizza imperatively, you tell your helper each of the instructions clearly like a recipe:

  1. Heat the over to 550°F or higher for at least 30 minutes
  2. Prepare one-pound of dough
  3. Roll out the dough to make a 10-inch circle
  4. Spoon the tomato sauce onto the center of the pizza and spread it out to the edges
  5. Place toppings (including onions, sliced mushrooms, pepperoni, cooked sausage, cooked bacon, diced peppers and cheese) on top of the sauce
  6. Bake the pizza for 5 minutes

On the other hand, if you cook it in a declarative way, you do not need to specify the step by step instructions but just describe how you would like the pizza cooked. Thick or thin crust? Pepperoni and bacon, or just a classic Margherita with tomato sauce? 10-inch or 16-inch? The helper will figure out the rest and cook the pizza for you.

That's the core difference between the term imperative and declarative. Now back to UI programming. Imperative UI programming requires developers to write detailed instructions to layout the UI and control its states. Conversely, declarative UI programming lets developers describe what the UI looks like and what you want to respond when a state changes.

The declarative way of coding would make the code much easier to read and understand. Most importantly, the SwiftUI framework allows you to write way less code to create a user interface. Say, for example, you are going to build a heart button in an app. This button should be positioned at the center of the screen and is able to detect touches. If a user taps the heart button, its color is changed from red to yellow. When a user taps and holds the heart, it scales up with an animation.

Figure 3-2. The implementation of an interactive heart button
Figure 3-2. The implementation of an interactive heart button

Take a look at figure 3-2. That's the code you need to implement the heart button. In around 20 lines of code, you create an interactive button with a scale animation. This is the power of the SwiftUI declarative UI framework.

Building Your First App Using SwiftUI

That's enough for the background information of the SwiftUI framework. As I always said, you have to get your hands dirty to learn programming. Now it's time to fire up Xcode and write your first iOS app in SwiftUI. For the rest of the chapter, you will write code to try out different UI components such as Text, Image, Stack Views. Furthermore, you will learn how to detect tap gesture. By combining all the techniques, you will eventually build your first app.

First, fire up Xcode and create a new project using the App template under the iOS category. Choose Next to proceed to the next screen.

Figure 3-3. Choose the App template
Figure 3-3. Choose the App template

Next, set the name of the project to HelloWorld. Hello World is a program for the first-time programmer to create. It's a very simple program that outputs "Hello, World" on the screen of a device. While your first app will be more complicated than that, let's follow the programming tradition and name the project "HelloWorld".

Figure 3-4. Fill in the project options
Figure 3-4. Fill in the project options

The organization identifier is a unique identifier of your app. Here I use com.appcoda but you should set it to your own value. If you have a website, set it to your domain in reverse domain name notation. Otherwise, you may use "com.". For instance, your name is Pikachi. Fill in the organization identifier as "com.pikachi".

Xcode now supports two ways to build user interace. Since this book is about SwiftUI, please set the Interface option to SwiftUI. For the programming language, you can set it to Swift.

For both Use Core Data and Include Tests options, you can leave them unchecked.

Click "Next" to continue. Xcode then asks you where to save the "HelloWorld" project. Pick any folder (e.g. Desktop) on your Mac. You may notice there is an option for source control. Just deselect it. Meanwhile, we do not need to use the option. Click "Create" to continue.

After you confirm, Xcode automatically creates the "Hello World" project. The screen will look like the screenshot shown in figure 3-5.

Figure 3-5. Xcode workspace with source code editor and preview pane
Figure 3-5. Xcode workspace with source code editor and preview pane

Familiarize Yourself with Xcode Workspace

Before we start to implement the Hello World app, let's take a few minutes to have a quick look at the Xcode workspace environment. In the left pane is the project navigator. You can find all your project files in this area. The center part of the workspace is the editor area. You do all the editing stuff here (such as editing the project setting, source code file, user interface) in this area.

Depending on the type of file, Xcode shows you different interfaces in the editor area. For instance, if you select HelloWorldApp.swift in the project navigator, Xcode displays the source code in the center area. Xcode comes with several themes for you to choose from. Say, if you prefer dark themes, you can go up to the menu and choose Xcode > Preferences > Themes to change it.

If you select the ContentView.swift file, Xcode automatically resizes the code editor and displays an extra pane right next to it. This extra pane is the preview pane for the ContentView. If you can't see the design canvas, you can go up to the Xcode menu and choose Editor > Canvas to enable it.

By default, the instant preview is paused. You can click the Resume button to render the app preview. After you click the button, Xcode renders the preview in a simulator that you choose in the simulator selection (e.g. iPhone 12 Pro).

Figure 3-6. Previewing the app
Figure 3-6. Previewing the app

To give yourself more space for writing code, you can hide both the project navigator and the inspector (see figure 3-6). If you want to resize the preview, use the magnifying icons at the bottom-right corner.

Run Your App for the First Time

Until now, we haven't written a single line of code. The code in ContentView is generated by Xcode. Before we write our own code, let's try to run the app using the built-in simulator. This will give you an idea how to build and test your app in Xcode. In the toolbar, you should see the Run button.

Figure 3-7. Test the app in a simulator
Figure 3-7. Test the app in a simulator

The Run button in Xcode is used to build an app and run it in the selected simulator. By default, the Simulator is set to iPod touch. If you click the iPod touch button, you'll see a list of available simulators such as iPhone SE and iPhone 12 Pro. Let's select iPhone 12 Pro as the simulator, and give it a try.

Once selected, you can click the Run button to load your app in the simulator. Figure 3-7 shows the simulator of an iPhone 12 Pro. To terminate the app, simply hit the Stop button in the toolbar.

Try to select another simulator (e.g. iPhone 12 mini) and run the app. You will see another simulator showing up on screen. The latest version of Xcode allows developers to run multiple simulators simultaneously.

Figure 3-8. Running multiple simulators at the same time
Figure 3-8. Running multiple simulators at the same time

The simulator works pretty much like a real iPhone. You can click the home button (or press shift-command-h) to bring up the home screen. It also comes with some built-in apps. Just play around with it to familiarize yourself with Xcode and simulator environment.

Working with Text

Now that you should be familiar with the Xcode workspace, it's time to check out the SwiftUI code. The sample code generated in ContentView already shows you how to display a single line of text. You initialize a Text object and pass to it the text (e.g. Hello World) to display like this:

Text("Hello World")

The preview canvas then displays Hello World on screen. This is the basic syntax for creating a text view. You're free to change the text to whatever value you want and the canvas should show you the change instantaneously.

Figure 3-9. Changing the text
Figure 3-9. Changing the text

Changing the Font Type and Color

In SwiftUI, you can change the properties (e.g. color, font, weight) of a control by calling methods that are known as Modifiers. Let's say, you want to bold the text. You can use the modifier fontWeight and specify your preferred font weight (e.g. .bold) like this:

Text("Stay Hungry. Stay Foolish.").fontWeight(.bold)

You access the modifier by using the dot syntax. Whenever you type a dot, Xcode will show you the possible modifiers or values you can use. For example, you will see various font weight options when you type a dot in the fontWeight modifier. You can choose bold to bold the text. If you want to make it even bolder, use heavy or black.

Figure 3-10. Attaching the fontWeight modifier
Figure 3-10. Attaching the fontWeight modifier

By calling fontWeight with the value .bold, it actually returns you a new view that has the bolded text. What is interesting in SwiftUI is that you can further chain this new view with other modifiers. Say, if you want to make the bolded text a little bit bigger, you write the code like this:

Text("Stay Hungry. Stay Foolish.").fontWeight(.bold).font(.title)

The font modifier lets you change the font properties. In the code above, we specify the title font type in order to enlarge the text. SwiftUI comes with several built-in text styles including title, largeTitle, body, etc. If you want to further increase the font size, replace .title with .largeTitle.

The code will be hard to read if we continue to chain more modifiers in the same line of code. Therefore, we usually write the code in the following format by breaking it into multiple lines:

Text("Stay Hungry. Stay Foolish.")
    .fontWeight(.bold)
    .font(.title)

The functionality is the same but I believe you'll find the code above more easy to read. We will continue to use this coding convention for the rest of this book.

The font modifier also lets you change the text design. Let's say, you want the font to be rounded. You can write the font modifier like this:

.font(.system(.title, design: .rounded))

Here you specify to use the system font with title text style and rounded design. The preview canvas should immediately respond to the change and show you the rounded text.

Figure 3-11. Changing the font style
Figure 3-11. Changing the font style

Working with Buttons

Button is another common UI components you need to know. It is a very basic UI control which has the ability to handle users' touch, and trigger a certain action.

To create a button using SwiftUI, you just need to use the code snippet below to create a button:

Button {
    // What to perform
} label: {
    // How the button looks like
}

When creating a button, you need to provide two code blocks:

  1. What action to perform - the code to perform after the button is tapped or selected by the user.
  2. How the button looks - the code block that describes the look & feel of the button.

For example, if you just want to turn the Hello World label into a button, you can update the code like this:

struct ContentView: View {
    var body: some View {

        Button {

        } label: {
            Text("Hello World")
                .fontWeight(.bold)
                .font(.system(.title, design: .rounded))
        }

    }
}

The Hello World text becomes a tappable button, even though we didn't specify any follow-up actions. The text color is automatically changed to blue because this is the default color for buttons in iOS.

Figure 3-12. Run the app to test the button
Figure 3-12. Run the app to test the button

You have to run the app before you can try out the button. Click the Play button in the simulator dock (figure 3-12) to switch to the interactive mode. Though the button doesn't perform any actions, you should see a blink effect when tapping the button.

Customizing the Button Style

Similar to Text, you can customize the color of the button by attaching some modifiers. For example, you can attach the foregroundColor and background modifiers to make a purple button.

Button {

} label: {
    Text("Hello World")
        .fontWeight(.bold)
        .font(.system(.title, design: .rounded))
}
.foregroundColor(.white)
.background(Color.purple)

After the change, your button should look like the figure below.

Figure 3-13. Changing the button's color
Figure 3-13. Changing the button's color

As you can see, the button doesn't look very good. Wouldn't it be great to add some space around the text? To do that, you can use the padding modifier like this:

Figure 3-14. Attaching the padding modifier
Figure 3-14. Attaching the padding modifier

SwiftUI also makes it very easy to create a button with rounded corners. You just need to attach the cornerRadius modifier to the Button view and specify the corner radius like this:

.cornerRadius(20)

The value of cornerRadius describes how rounded the corners of the button. A larger value produces a more rounded corner, while a smaller value achieves a shaper corner. You can change the corner radius to other values to see the effect.

Figure 3-15. Creating a button with rounded corners
Figure 3-15. Creating a button with rounded corners

Adding the Button Action

A button is not useful if it doesn't perform any actions. What we are going to implement is to make the button speak. When the button is tapped, it will speak "Hello World!"

This doesn't sound easy, right? We have to deal with text-to-speech. That said, Apple has made this very easy even for beginners.

As I mentioned before, the iOS SDK has bundled many amazing frameworks for developers to use. We are now using the SwiftUI framework to create user interface. To perform text-to-speech, we can rely on the AVFoundation framework.

Before we can use the framework, we have to import it at the beginning of the code. Right below import SwiftUI, insert the following import statement:

import AVFoundation

Next, update the code of Button like this:

Button {

    let utterance = AVSpeechUtterance(string: "Hello World")
    utterance.voice = AVSpeechSynthesisVoice(language: "en-GB")
    let synthesizer = AVSpeechSynthesizer()
    synthesizer.speak(utterance)

} label: {
    Text("Hello World")
        .fontWeight(.bold)
        .font(.system(.title, design: .rounded))
}
.padding()
.foregroundColor(.white)
.background(Color.purple)
.cornerRadius(20)

Here, we added 4 lines of code in the action block. That's the code you need to instruct iOS to speak a piece of text for you. The first line of code specifies the text (i.e. "Hello World"), while the second line of code sets the voice to British English. The rest of the lines are to create the speech synthesizer and speak out the text with the chosen voice.

To test the app, click the Play button in the simulator dock. Then click the Hello World button to test out text-to-speech. If you can't hear the voice, please check if your speaker is turned on and not muted.

Figure 3-16. Adding the action block for the button
Figure 3-16. Adding the action block for the button

Introducing Stack Views

Your first app works great, right? With just around 10 lines of code, you already created an app that can translate text into speech. Presently, the button is designed to speak "Hello World". What if you want to create another button, which speaks a different sentence or words, above the Hello World button? How can you arrange the UI layout?

SwiftUI provides a special type of views known as Stack Views for you to construct complex user interfaces. More specifically, stack views lets you arrange multiple views (or UI components) in vertical or horizontal direction. For example, if you want to add a new button above the Hello World button, you can embed both buttons in a VStack like this:

VStack {

  // New Button

  // Hello World Button
}

VStack is a vertical stack view for laying out views vertically. The order of the views inside a VStack determines how the embedded views are arranged. In the code above, the new button will be placed on the top of the Hello World button.

Now let's modify the actual code to see the changes in action. To embed the Hello World button in a VStack, you can hold the command key and click Button. In the context menu, choose Embed in VStack. Xcode then wraps the Hello World button in a VStack view.

Figure 3-17. Embed the button in a VStack
Figure 3-17. Embed the button in a VStack

Once you embedded the Hello World button in the VStack, duplicate the code of the Hello World button to create the new button like this:

VStack {
    Button {

        let utterance = AVSpeechUtterance(string: "Happy Programming")
        utterance.voice = AVSpeechSynthesisVoice(language: "en-GB")
        let synthesizer = AVSpeechSynthesizer()
        synthesizer.speak(utterance)

    } label: {
        Text("Happy Programming")
            .fontWeight(.bold)
            .font(.system(.title, design: .rounded))
    }
    .padding()
    .foregroundColor(.white)
    .background(Color.yellow)
    .cornerRadius(20)

    Button {

        let utterance = AVSpeechUtterance(string: "Hello World")
        utterance.voice = AVSpeechSynthesisVoice(language: "en-GB")
        let synthesizer = AVSpeechSynthesizer()
        synthesizer.speak(utterance)

    } label: {
        Text("Hello World")
            .fontWeight(.bold)
            .font(.system(.title, design: .rounded))
    }
    .padding()
    .foregroundColor(.white)
    .background(Color.purple)
    .cornerRadius(20)
}

The label of the new button is changed to Happy Programming and its background color is also updated to Color.yellow. On top of these changes, the string parameter of AVSpeechUtterance is changed to "Happy Programming." You can refer to figure 3-18 for the changes.

Figure 3-18. Embed the button in a VStack
Figure 3-18. Embed the button in a VStack

This is how you arrange two buttons vertically. You can run the app for a quick test. The Happy Programming button works exactly the same as the Hello World button, but it speaks "Happy Programming!"

Understanding Methods

Before we end this chapter, let me introduce another basic programming concept. Take a look at the code of ContentView again. There are quite a lot of similarities and duplicated code for the two buttons. One duplicate is the code in the action block of the buttons.

Figure 3-19. The code block is very similar
Figure 3-19. The code block is very similar

Both block of code are nearly the same except that the text to read is different. One is "Happy Programming", the other is "Hello World."

In Swift, you can define a method for this type of repetitive tasks. In this case, we can create a method named speak inside ContentView like this:

func speak(text: String) {
    let utterance = AVSpeechUtterance(string: text)
    utterance.voice = AVSpeechSynthesisVoice(language: "en-GB")
    let synthesizer = AVSpeechSynthesizer()
    synthesizer.speak(utterance)
}

The func keyword is used to declare a method. Following the func keyword is the name of the method. This name identifies the method and makes it easy for the method to be called elsewhere in your code. Optionally, a method can take in parameters as input. The parameters are defined within the parentheses. Each of the parameters should have a name and a type, separated by a colon (:). In this example, the method accepts a text parameter which has the type String.

In the method, that's the 4 lines of code for converting text into speech. The only change is this line of code:

let utterance = AVSpeechUtterance(string: text)

We set the string parameter to text, which is the text passed by the method caller.

Now that we have created the method, how can we call it? You just need to use the method name and pass it the required parameter like this:

speak(text: "Hello World")

Let's go back to the ContentView struct to modify the code. First, create the speak(text: String) method as shown in figure 3-20. Next, you can replace the action block of both button by calling the speak method.

Figure 3-20. Remove the duplicated code by creating the speak method
Figure 3-20. Remove the duplicated code by creating the speak method

This new method doesn't change the functionality of the application. Both buttons work exactly the same as before. However, as you can see from the final code, it's easier to read and much cleaner.

And, what if you need to introduce another text-to-speech button to the application? You no longer need to duplicate the 4 lines of code but just call the speak method with the text to read. This is why we need to group common operations into methods.

Exercise

In order to help you fully understand how to work with buttons and methods, here is a simple exercise for you. Your task is to modify the existing code and build a "Guess These Movies" app. The UI and functions are very similar to the Hello World app. Each button displays a set of emoji icons. The player's task is to guess the movie's name from those emojis. By tapping the button, the app will speak out the correct answer. For example, when the player taps the button in blue, the app reads "The answer is Ocean 11!"

Figure 3-21. Building a Guess these Movies app
Figure 3-21. Building a Guess these Movies app

Summary

Congratulations! You've built your first iPhone app. It's a simple app, but I believe you already have a better understanding of Xcode, SwiftUI, and the built-in frameworks provided by the iOS SDK. It's easier than you thought, right?

To access the full version of the book, please get the full copy here. You will also be able to access the full source code of the project.

results matching ""

    No results matching ""