Practical State Machines with GameplayKit

In this tutorial, you’ll convert an iOS app to use a state machine for navigation logic using GameplayKit’s GKStateMachine. By Keegan Rush.

Leave a rating/review
Download materials
Save for later
Share

Managing state is hard, but you have many techniques to manage state in a regular iOS app. The GameplayKit framework hides one useful technique: GKStateMachine.

State machines are often used in game programming. However, their utilities don’t end there. Programmers have solved problems with state machines for ages. GKStateMachine lives within a framework for game development, but don’t let that stop you. There’s no reason you can’t use it inside any other iOS app that has state to manage.

Some of the uses of state machines could be to make sense of complicated business logic, to control the state of a view controller or to manage navigation. In this tutorial, you’ll refactor an app to use a state machine to control navigation.

By the time you’re done with this tutorial, you’ll gain a deeper understanding of state machines and learn how to:

  • Simplify the logic in an app with a state machine.
  • Use GKStateMachine to configure your state machine.
  • Control the flow of your state machine by defining valid transitions.

Getting Started

To start off, download the sample project using the Download Materials button at the top or bottom of this tutorial. Kanji List is an app for learning Kanji characters from the Japanese language that’ll surely be indispensable for your next trip to Tokyo. The app is from the RayWenderlich Coordinator Tutorial for iOS.

The app shows a list of kanji. Clicking on a kanji will show you the the meaning of that kanji and a list of words that use the kanji. Clicking on any of those words will take you to a list of kanji in the word, where you can repeat the process to your heart’s content.

Kanji List functionality

In this tutorial, you’ll refactor the navigation logic of Kanji List to make use of a state machine. Currently, Kanji List uses the coordinator pattern for navigation. This is great; it means that the navigation code has already been extracted from the view controllers. You’ll only need to add a state machine to organize the coordinators.

If you’re unfamiliar with the coordinator pattern, don’t worry. It’s a simple pattern for handling an app’s flow between view controllers. If you want to learn more, take a quick look at the Coordinator Tutorial for iOS.

Understanding State Machines

A state machine is a mathematical abstraction for representing a system that can be in only one state at a time. Sounds complicated, right? It’s actually very simple and a very useful way to look at some problems. Think about the battery in an iPhone, for example. You can look at a battery as a state machine:

Battery State Machine

This state machine has four states:

  1. Charging: The phone is plugged in and charging.
  2. Fully Charged: The battery is full and the phone is receiving power from the charger.
  3. Discharging: The phone is unplugged and relying on the battery for power.
  4. Flat: The battery has run out of charge.

Plugging the phone into a charger puts it into the Charging state. From there, it can transition to the Discharging state when unplugged. If you leave the phone plugged in until the battery reaches 100%, it will enter the Fully Charged state. When you unplug the phone, if you let the battery discharge fully, it’ll enter the Flat state.

The state machine represents which state transitions are valid. A battery doesn’t go flat while it’s charging (unless you need a new battery!), so there is no transition from Charging to Flat in the state machine.

Different Between States

First, you need to define the different states to represent the navigation in Kanji List as a state machine. Once you’ve opened the starter project in Xcode, build and run the app.

The app starts off with a list of all the supported kanji. This will be the All state. Next, tap on a kanji to show the Detail screen. This will be the Detail state. Finally, tap on one of the words that use the kanji to go to a list of words in the kanji, which you will call the List state.

Kanji List States

Great! Since Kanji List is a simple app, these three states are enough to represent the functionality of the app. As the app grows in functionality, the state machine will be a helpful tool to keep things under control.

Transitioning Between States

Defining the different states in an app helps you to better understand the way the app works. But, without defining the valid transitions between states, the state machine is incomplete.

Each screen contains an All button in the navigation bar to transition to the All screen. That means a transition from the Detail screen or the List screen to the All screen is valid.

Tapping a word takes the app to the List screen, which shows all the kanji in a word. So, you can only transition to the List screen by tapping on a word via the Detail screen.

Additionally, tapping on a kanji navigates to the Detail screen. This means that a transition from the All screen or List screen to the Detail screen is valid.

Tying that all together presents this diagram of the state machine:

Kanji List State Machine

Creating the State Machine

Now, that’s enough talking about states. It’s time to write some code! First, create a file named KanjiStateMachine.swift under the State Machine group. Replace the import statement with this:

import UIKit
import GameplayKit.GKStateMachine

class KanjiStateMachine: GKStateMachine {
  let presenter: UINavigationController
  let kanjiStorage: KanjiStorage

  init(presenter: UINavigationController,
       kanjiStorage: KanjiStorage,
       states: [GKState]) {
    // 1
    self.presenter = presenter

    // 2
    self.kanjiStorage = kanjiStorage

    // 3
    super.init(states: states)
  }
}

While it isn’t required to subclass GKStateMachine, this subclass lets you store some important data that your states will need later. The initializer is a simple one, but here’s what’s going on:

  1. The app’s coordinator pattern uses a UINavigationController as a presenter for view controllers. The state machine will own the presenter.
  2. The KanjiStorage class is essentially the app’s dictionary. It stores all the kanji and the words that contain them. The KanjiStateMachine manages the KanjiStorage object for each state to use.
  3. GKStateMachine‘s initializer needs instances of each state you’re using, so pass it up to GKStateMachine.init(states:).

Next, open ApplicationCoordinator.swift. This is the root coordinator of the application that creates the root view controller and adds it to the app’s UIWindow. Add a new property for the state machine at the top of the class:

let stateMachine: KanjiStateMachine

At the end of init(window:), add the following to create the state machine:

stateMachine = KanjiStateMachine(
  presenter: rootViewController,
  kanjiStorage: kanjiStorage,
  states: [])

Because you haven’t created any GKState classes, you’ll just pass an empty array for the states for the time being.

Keegan Rush

Contributors

Keegan Rush

Author

Scott McAlister

Tech Editor

Tyler Bos

Editor

Aleksandra Kizevska

Illustrator

Kelvin Lau

Final Pass Editor

Richard Critz

Team Lead

Over 300 content creators. Join our team.