Chapters

Hide chapters

macOS Apprentice

Second Edition · macOS 15 · Swift 5.9 · Xcode 16.2

Section II: Building With SwiftUI

Section 2: 6 chapters
Show chapters Hide chapters

Section III: Building With AppKit

Section 3: 6 chapters
Show chapters Hide chapters

5. Beginning SwiftUI
Written by Sarah Reichelt

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

In Section 1, you installed Xcode and used various tools to run Swift code on your Mac. In this section, you’ll apply that knowledge to create an entire app for your Mac using Swift and SwiftUI.

Chapter 1 gave a tour of Xcode, explained the basic structure of a Mac app project and showed you how SwiftUI views and previews work together. This chapter builds on that.

The app you’re about to create is a word guessing game called Snowman. The computer picks a word and you enter letters to guess the word. Every time you choose an incorrect letter, part of the snowman disappears. If the snowman vanishes completely before you’ve guessed the word, you lose. :[

Snowman
Snowman

Setting Up Your App

Start Xcode as you’ve done many times now. Create a new project from the Welcome window or by selecting File ▸ New ▸ Project…. When you get to the template chooser, select macOS ▸ App. Click Next and set the details like this:

  • Product Name: Snowman
  • Team: If you have a developer team, select it, or leave this set to None.
  • Organization Identifier: Enter your reverse domain name as you did in Chapter 1.
  • Bundle Identifier: Xcode fills this in based on your previous entries.
  • Interface: SwiftUI
  • Language: Swift
  • Testing System: None
  • Storage: None

When your settings look like this, click Next:

Setting up the new project.
Setting up the new project.

Select where you want to save your project and click Create.

The project window appears and you’re ready to code.

What is SwiftUI?

When developing apps for the Mac, you have a choice of two layout frameworks. AppKit is the older one, and you’ll learn about it later. If you’ve done any iOS programming, it’s similar to UIKit. SwiftUI is the new framework, which Apple describes as “a modern way to declare user interfaces for any Apple platform”.

Laying Out the User Interface

Looking at the app image at the start of this chapter, there’s a sidebar listing the games played and a larger area to display the current game.

// 1
NavigationSplitView {
  // 2
  Text("Sidebar")
} detail: {
  // 3
  Text("Game view")
}
Previewing the split view.
Ygekiejahr glu tkhun peod.

Splitting Up the Subviews

Your views will get more complicated, so it’s a good idea to split them out into their own files and structures.

The view files in a folder.
Lci mooc soyox it o henzal.

// 1
struct SidebarView: View {
  // 2
  var body: some View {
    // 3
    Text("Hello, World!")
  }
}
var body: some View {
  // 1
  NavigationSplitView {
    // 2
    SidebarView()
  } detail: {
    // 3
    GameView()
  }
}
Separated subviews
Sijovunah jitgoovb

Designing the Game View

One of the fundamentals of SwiftUI is that you can build complex views from a set of component views. It looks like the game view has a lot of parts, but if you break it down into components, you can add them one at a time. That way you don’t lose yourself in complexity.

The game view components
Qbu zuwa neel polquvibjm

The Snowman Images

SwiftUI has an Image view that can display a picture, but first, you need the images to show. Open the downloaded materials for this chapter and look in the assets folder. There’s a folder called Snowmen with images for both light and dark mode.

Importing images.
Iphohgozx avakeh.

Snowman images
Lhatlor aqiyet

// 1
Image("0")
  // 2
  .resizable()
  // 3
  .aspectRatio(contentMode: .fit)
  // 4
  .frame(width: 230)
Previewing an image.
Jcekauwefc ec ebowu.

Stacking

SwiftUI offers various stack views for arranging components in your layout. HStack arranges them horizontally, VStack arranges them vertically and ZStack piles them on top of each other.

Text("Enter a letter to guess the word.")
  .font(.title2)

Looping Through Views

To create the letters view, you’ll loop through the letters in the word, using Text views to show each letter and overlaying this with a rounded rectangle to draw the box.

let word = ["S", "N", "O", "W", "M", "A", "N"]
// 1
HStack {
  // 2
  ForEach(word, id: \.self) { letter in
    // 3
    Text(letter)
      .font(.title)
      .bold()
      .frame(width: 20, height: 20)
      .padding()
      // 4
      .overlay(
        // 5
        RoundedRectangle(cornerRadius: 10)
          .stroke(lineWidth: 2)
          // 6
          .foregroundStyle(Color.accentColor)
          // 7
          .padding(2))
  }
}
The Word view
Sda Feyt doiv

Buttons

Now, you’ll add the New Game button. It goes in the VStack underneath the letters view. Collapse the HStack that contains the ForEach loop and add a blank line after it.

// 1
Button("New Game") {
  // 2
  print("Starting new game.")
}
// 3
.keyboardShortcut(.defaultAction)
Running the app to see the default button.
Qugrosh pso iys fo cuu vcu jimiolr qopcax.

Adding the Final Components

The last section is the area that shows the letters guessed and allows you to guess new ones. First, you’ll need some test data to hold the guesses.

let guesses = [ "E", "S", "R", "X"]
// 1
HStack {
  // 2
  Text("Letters used:")
  // 3
  Text(guesses.joined(separator: ", "))
}
// 1
LabeledContent("Guess a letter:") {
  // 2
  Text("Q")
}
GameView preview
ZemiPaop qqajeed

Spacing

When you look back at the original design, you’ll see that you have all the parts, but SwiftUI has clustered them into the center.

VStack spacing
CPlogs chuhemw

VStack(spacing: 30.0) {
  Spacer()    // NEW
  
  Text("Enter a letter to guess the word.")
Spacer()    // NEW

Button("New Game") {
  print("Starting new game.")
}
.keyboardShortcut(.defaultAction)

Spacer()    // NEW
Fixing the spacing.
Woxugl bgu xpesorr.

Framing the Window

Time for another run, so press Command-R to build and run the app:

Running the app.
Pidpahr jdo okp.

Image("2")
  .resizable()
  .aspectRatio(contentMode: .fit)
  .frame(width: 230)

Spacer()    // NEW

VStack(spacing: 30.0) {
}    // end of VStack
.padding()

Spacer()    // NEW
Large window
Jiwje nuvwun

Tidying Your Code

You’ve finished the layout work for your GameView, but GameView.swift has become long and complicated. Now is a good time to separate out some of this code into subviews.

LettersView()
GuessesView()
struct GuessesView: View {
  let guesses = [ "E", "S", "R", "X"]

  var body: some View {
    VStack {
      HStack {
        Text("Letters used:")
        Text(guesses.joined(separator: ", "))
      }
      
      LabeledContent("Guess a letter:") {
        Text("Q")
      }
    }
  }
}

Key Points

  • SwiftUI is a framework that allows you to layout your user interface programmatically. You tell SwiftUI what you want and it decides how to do it.
  • You build your interface by assembling components and grouping them into stacks.
  • Modifiers change the views and you can chain multiple modifiers together.

Where to Go From Here

Your game view interface is complete. In the next chapter, you’ll start making it live with real data instead of placeholders.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2025 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now