Skip to main content

Creating your first iOS App with SwiftUI

This guide is for beginning mobile app developers. You will need a Mac computer, running a recent version of Xcode. The version of Xcode used in this guide is 14.1 (December 2022).

At the end of this short tutorial, you will have built your first iOS app and run it on the iOS Simulator to see what it would look like on a phone.

UIKit vs SwiftUI

Apple supports two different ways of building the user interface for iOS applications, UIKit and SwiftUI. The UIKit framework is the original iOS user interface development technology. SwiftUI is a newer framework that is similar to the React Javascript framework for web. You can use them together, but for beginning programmers, it's best to start with one or the other.

This tutorial uses SwiftUI, but we also have a very similar tutorial that uses UIKit. When you are just starting out, my suggestion is to try both of them out, and see which one you prefer.

Install Xcode

If you don't have Xcode yet, download Xcode from the Mac App Store, and then open it up. It will offer to install additional components, which you will need to let it do. This can take a while.

You can also install a specific version of Xcode from the Apple Developer portal, if you need to go back to a previous version.

Open Xcode

Once you have Xcode installed, start it up. You'll see a friendly Welcome to Xcode window appear.

We will be creating a new Xcode project, so choose the first option on the Welcome window.

Welcome to Xcode window

Next, a list of project template appears. Xcode will default to showing a Multiplatform app as the default, but we want to choose iOS in the small tab bar at the top of the window.

Xcode template chooser

After choosing iOS, you will see a different list of templates - we are building an app, so click App and then click Next to move on in the process.

Xcode iOS templates

Xcode Project Options

After choosing one of the Xcode templates, you will need to fill in some details about your project. The three things you need to do are:

  • Pick a project name
  • Use an organization identifier
  • Make sure the interface is SwiftUI (not Storyboard)

The project name can be FirstSwiftUIApp or something similar. The organization identifier should be a domain name you control, in reverse order - such as com.buildingmobileapps or com.jefflinwood. If you don't have your own domain, you can make one up that is unique.

Xcode will initially default to using SwiftUI as the interface technology, instead of UIKit. If you create a project with Storyboard/UIKit, that will be the default until you change it.

Xcode project options

Fill in the project name and organization identifier, choose SwiftUI as the Interface, and then click Next.

Xcode will offer to save your project on your Desktop - you can put it wherever you like. The checkbox for creating a Git repository on your Mac will be checked. We won't be using Git in this guide, but we recommend that you leave this checked by default.

Xcode project location

Save the project by clicking Create, and then Xcode will open your new project.

The SwiftUI Project in Xcode

After saving the project, Xcode will open up your project, starting with the ContentView.swift file. You may see your computer doing a lot of processing - Xcode will show you a live preview of your SwiftUI View, but it can be slow to start initially. After Xcode finishes what it needs to do, your Xcode window will look similar to this:

Starting the Xcode project

With SwiftUI, we write all of our user interface as Swift code - it is not the same Swift objects we used for UIKit and Storyboard development. Taking a look at the project we generated, we have two important files:

  • FirstSwiftUIAppApp - the main application
  • ContentView - the only screen in our app

We won't need to modify the FirstSwiftUIAppApp file, but taking a look at the code that Xcode generated, we can see that the ContentView gets loaded from this file:

Generated App Code
import SwiftUI

@main
struct FirstSwiftUIAppApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}

If we dig into the ContentView that Xcode created, we can see that the code describes the user interface we are seeing in the live preview:

Generated ContentView code
import SwiftUI

struct ContentView: View {
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, world!")
}
.padding()
}
}

struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

What probably stands out is that there are two struct structures in one file. The preview in Xcode gets created from the ContentView_Previews structure at the bottom. If you have a view that takes arguments, or has a data source, you can populate it programmatically inside this preview structure. In this guide, we won't need to do anything like that.

Our focus will be on the ContentView struct. As you can see, it extends a SwiftUI View structure, and then declares a body.

The body contains a VStack struct, which is a vertical stack. The VStack can contain zero or more views, and will align them vertically, top to bottom. There is a corresponding HStack that we are not using that aligns views horizontally. If you nest vertical stacks within horizontal stacks, and vice versa, you can build out your user interface designs.

Inside the VStack you will see an Image view and a Text view. The Text view displays a piece of text supplied to it. You can add modifiers to a view to change its behavior. Some of these modifiers for text include the foreground and background colors and the font. Let's make an easy change and have the text "Hello World" show up in blue.

Add the modifier .foregroundColor(.blue) to the Text view:

Use the color blue
    Text("Hello, world!").foregroundColor(.blue)

The preview should automatically update to show the text as blue:

Changing Text to Blue

Using state in SwiftUI

SwiftUI is reactive, so we don't explicitly change the button's text like we might in UIKit. Instead, we can setup a state variable in our view that holds data we want to display. When we change the contents of that variable, the view will re-render the user interface with any changes that need to be shown.

We will create a button to change the text on the screen, but first we need to setup a state variable and then tell the Text view to display the contents of that variable.

Let's refactor our view a little. Start by creating a variable named myText. We declare a variable using the var keyword, but then we add the @State annotation to signify that SwiftUI will be managing this variable for us as a state property.

@State private var myText = "Hello, world!"

What are state properties? They're a way that we can make our user interfaces reactive. You can pass a state property in as the value for a view, and if your code sets a new value for that property, SwiftUI will automatically update the views.

Using this approach, we can avoid writing code that updates the user interface based on instance variables. Instead, we can express our user interface in terms of the state, and let SwiftUI manage it for us. This is very similar to the React framework for web development.

After adding the state variable, we need to adjust the Text to use the myText state property instead of the hard-coded string "Hello, world!".

Adding a state variable
struct ContentView: View {
@State private var myText = "Hello, world!"

var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text(myText).foregroundColor(.blue)
}
.padding()
}
}

You won't see any changes in how your screen looks in the preview, as we're just doing a little refactoring here.

Adding a button

Of course, we want our app to actually do something, so let's add a button to our project. With buttons, we can define an action to take when someone taps or clicks the button. This action could be inline, or a separate function. Our example here will use a separate function for clarity.

Let's start by adding a Button into our VStack after the Text view. We can define the label as well as an action to take. This won't compile until we define the function sayHi, so the preview will be broken for a bit.

Another thing we will do to give our button a bit of breathing room in our user interface is to use the padding modifier. Try taking it out, or adding it to the Text or Image elements to see how the view looks with and without it.

Button("Say hi!", action: sayHi).padding()

We'll also need to create a sayHi function to go along with our button.

func sayHi() {
myText = "Hi!"
}

Using the func keyword, we declare a Swift function with no arguments, and then set the value of the myText state property.

Notice we don't need to get a reference to the Text view to make it change. If we were using UIKit, we would have to use an outlet or an id to change the label directly.

Combining those two changes with the ContentView view we've been working on, we should have code that looks like this:

Adding a button
struct ContentView: View {

@State private var myText = "Hello, world!"

func sayHi() {
myText = "Hi!"
}

var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text(myText).foregroundColor(.blue)
Button("Say hi!", action: sayHi).padding()
}
.padding()
}
}

After preview loads up, your screen should look similar to this:

Added Button

Go ahead and click the button and you should see the text contents change.

Clicked Button

This demonstrates the basics of using state variables with your SwiftUI views, along with how buttons work. There's certainly a lot more to cover with SwiftUI, but hopefully this is enough to get you started!