Design Patterns in Swift: State Pattern

If your objects can have multiple states, then you should consider implementing a state pattern. In this article we'll cover some theory on state pattern, and then we'll go over an example on how to implement it. Hopefully, by the end of the article, you'll be familiar with the state pattern.

If your objects can have multiple states, then you should consider implementing a state pattern. In this article we’ll cover some theory on state pattern, and then we’ll go over an example on how to implement it. Hopefully, by the end of the article, you’ll be familiar with the state pattern.

The State Pattern

As you’ve worked on your projects, you’ve probably encountered classes that had internal states. Let’s say you have a class for downloading large images from a server. This class could be in multiple different states: requesting, downloading, processing, saving… to name a few.

In our examples we’ll use a vehicle. Our vehicle can be in a stopped state, it can be moving or automatically parking. The vehicle will have its functions, like brake or park. Depending on the state the vehicle is in, calling the brake function will have different effects. There’s no effect on calling the brake function if the vehicle is stopped and calling a brake function on a vehicle that’s automatically parking will cancel the parking operation.

The vehicle will manage its state internally, we won’t really know, or care what state it’s in. As you’ve noticed from the above paragraph, calling a function will produce different results based on the state the object is in. From your perspective it will look like the object itself changed. This brings us to the definition of the state pattern:

State pattern will allow an object to change its behaviour when its internal state changes. The object will appear to change its class.

That pretty much covers the theory. Let’s go over some diagrams next.

Vehicle States

We’ll implement a state pattern on a vehicle class. Our vehicle will have three distinct states as you can see on this diagram:

Vehicle can change states, but there are some rules to follow. For example, you can’t move from a moving state to a parking state directly, you have to transition to a stopped state first.

If you’re thinking about how to implement this behaviour into your vehicle class, you might be thinking of using enums to store the state information in a private variable of the vehicle class. Imagine how your functions would look like, you would end up with a lot of switch cases in your code. Your vehicle class would become pretty big and difficult to maintain.

What we’ll do is separate each of the ‘cases’ or states into a class of its own. The vehicle will have a reference to the current state of the vehicle, and the state classes will have a reference back to the vehicle. This will allow them to control the current state of the vehicle. Here’s a simple diagram of our class hierarchy:

Let’s see this in action and get coding…

The Code

We’ll keep things simple. Our vehicle class will have only three functions, a variable to store the speed and some factory methods to create states:

import Foundation

protocol VehicleProtocol: class
{
    // MARK: - Vehicle State
    var speed: Int { get set }
    func setState(_ state: VehicleState)
    
    // MARK: - Vehicle Controls
    func accelerate()
    func brake()
    func park()
    
    // MARK: - State Getters
    func getStoppedState() -> VehicleState
    func getMovingState() -> VehicleState
    func getParkingState() -> VehicleState
}

A class that’s using the vehicle would normally interact with the vehicle only by calling one of the three ‘vehicle controls’ functions. The other functions/variables are meant to be used by the state classes.

Calling any of the control functions would just forward that function call to the state, and the current vehicle state would handle it:

// MARK: - Vehicle Controls
func accelerate() {
    state?.accelerate()
}
    
func brake() {
    state?.brake()
}
    
func park() {
    state?.park()
}

Our vehicle will also have factory methods that will create vehicle states:

// MARK: - State Getters
func getStoppedState() -> VehicleState {
    return StoppedState(self)
}
    
func getMovingState() -> VehicleState {
    return MovingState(self)
}
    
func getParkingState() -> VehicleState {
    return ParkingState(self)
}

Now you’re beginning to see the pattern emerging here. Each state class has a pointer back to a vehicle and it can create new states. All that’s left is to implement the state classes.

State Classes

We’ll use a protocol for our vehicle states:

import Foundation

protocol VehicleState
{
    init(_ vehicle: VehicleProtocol)
    
    func accelerate()
    func brake()
    func park()
}

Every state class will have a reference back to the vehicle. And every state class will implement the vehicle control functions. Calling the vehicle control functions will have different meanings for each individual state class, as we’ll see in a moment.

Stopped State

Let’s check out the simplest of states, the stopped state:

class StoppedState: VehicleState
{
    private weak var vehicle: VehicleProtocol?
    
    required init(_ vehicle: VehicleProtocol) {
        self.vehicle = vehicle
    }
    
    func accelerate() {
        self.vehicle?.speed += 5
        if let movingState = self.vehicle?.getMovingState() {
            self.vehicle?.setState(movingState)
        }
    }
    
    func brake() {
        print("Can't brake... Vehicle is already stopped!")
    }
    
    func park() {
        if let parkingState = self.vehicle?.getParkingState() {
            self.vehicle?.setState(parkingState)
            parkingState.park()
        }
    }
}

When the vehicle is in the stopped state calling ‘accelerate’ will increase the vehicle speed by 5 (kph, mph… it doesn’t matter, really). It will also set the new state of the vehicle to the moving state. Calling the ‘brake’ function will have no effect, because the vehicle is not moving anyway. And calling the ‘park’ function will begin the automatic parking procedure.

Parking State

Parking state is a bit more interesting:

class ParkingState: VehicleState
{
    private weak var vehicle: VehicleProtocol?
    private var parking: Bool = false
    
    required init(_ vehicle: VehicleProtocol) {
        self.vehicle = vehicle
    }
    
    func accelerate() {
        print("Vehicle is automatically parking, you can't accelerate!")
    }
    
    func brake() {
        print("Automatic parking has been aborted")
        stopParking()
    }
    
    func park() {
        guard self.parking == false else {
            print("Vehicle is already parking")
            return
        }
        print("Vehicle is now parking")
        self.parking = true
        DispatchQueue.global().asyncAfter(deadline: .now() + 5) {
            self.stopParking()
        }
    }
    
    private func stopParking() {
        print("Vehicle has stopped parking")
        self.parking = false
        if let stoppedState = self.vehicle?.getStoppedState() {
            self.vehicle?.setState(stoppedState)
        }
    }
}

Here, we can see that calling the ‘brake’ function will stop the parking procedure. And calling ‘park’ will trigger a chain of events. You could argue that the content of this method might be more suitable for the ‘stopped state’ but, for the sake of simplicity, let’s keep it here.

Moving State

Moving state is also quite simple:

class MovingState: VehicleState
{
    private weak var vehicle: VehicleProtocol?
    
    required init(_ vehicle: VehicleProtocol) {
        self.vehicle = vehicle
    }
    
    func accelerate() {
        self.vehicle?.speed += 5
    }
    
    func brake() {
        self.vehicle?.speed -= 5
        if self.vehicle?.speed == 0, let stoppedState = self.vehicle?.getStoppedState() {
            print("Vehicle braked to a stop")
            self.vehicle?.setState(stoppedState)
        }
    }
    
    func park() {
        print("Can't park the vehicle while it's moving. You need to stop first")
    }
}

We can see here that we have a piece of logic in the ‘brake’ function that will change the state of the vehicle to stopped if the speed drops to 0.

Testing It Out

Let’s quickly test our vehicle out:

private func testVehicle() {
    let vehicle = Vehicle()
    vehicle.brake()
    vehicle.accelerate()
    vehicle.accelerate()
    vehicle.brake()
    vehicle.park() // prints: Can't park the vehicle while it's moving. You need to stop first
    vehicle.brake()
    vehicle.park()
}

We can see that our first call to the ‘park’ method will print out a message that the vehicle needs to be stopped and, after we brake, the second call will produce expected results. This simple test demonstrates how our vehicle seems to have changed implementation on the fly. Calling the same method on the same instance of a class is producing different results. And that’s the essence of the state pattern.

Conclusion

If you see a class with a lot of switch-case statements, it’s a good sign that you should consider implementing a state pattern. We could have easily used an enum in our vehicle to represent the current state. But imagine how the class would look like after a couple of states. The functions would get massive, the business logic will be in the case blocks, the code would easily get messy and hard to follow. This simple pattern solves those problems. You’ll end up with a couple more classes on your class diagram, but the code will be so much better and more readable. And the best thing is, adding new states would require minimal changes to the existing code.

State pattern is a very useful pattern to know, it might not be as popular as the other famous patterns, but it’s definitely worth knowing.

I hope you learned something new today and that we managed to clear things up a bit for you regarding the state pattern. You can find the example project on our GitHub repo.

As usual… Have a nice day πŸ™‚
~D;

More resources

21 thoughts on “Design Patterns in Swift: State Pattern

  1. Nikola Lajic

    Great article Dejan,

    you might have done it this way for simplicity’s sake, but my suggestion would be to split the VehicleProtocol to two protocols if some methods are only ment to be used by the states. For example like this:

    protocol VehicleProtocol: class
    {
    var speed: Int { get }

    func accelerate()
    func brake()
    func park()
    }

    protocol StatefulVehicleProtocol: VehicleProtocol
    {
    var speed: Int { get set }
    func setState(_ state: VehicleState)

    func getStoppedState() -> VehicleState
    func getMovingState() -> VehicleState
    func getParkingState() -> VehicleState
    }

    Then you change the VehicleState initializers to require the stateful protocol, and refer to vehicles outside of states by the VehicleProtocol. That way you lessen the chance of external code accidentaly calling “private” methods and messing up the state.

    Reply
    1. Dejan Agostini Post author

      Hey Nikola,

      Thank you very much πŸ™‚

      I wanted to implement a text-book version of the pattern from the ‘Gang of Four’, that’s why I did it this way. That being said, You’re absolutely right. If I was implementing it in production, I would probably do it the way you suggested.

      Thanks for reading the blog, I appreciate it πŸ™‚

      Have a nice day πŸ™‚
      ~D;

      Reply
    1. Dejan Agostini Post author

      Yes, it’s a similar pattern. They have very different usages, though. Memento is meant to be used to save the current state of the object so you can restore it to a previous state. Common usage of a memento is actually in game save files. While the state pattern is meant to actively manage states of the object.

      Reply
  2. Pingchen Su

    Nice article! I think you should also check out GKStateMachine! It provides nice integration with Xcode which allows you to debug with Apple’s GUI.

    Reply
  3. Dejan Agostini Post author

    Thanks πŸ™‚ Yeah, I know about the GameKit state machine, I wanted to keep things simple in this article and explain the pattern itself. Perhaps I’ll write something up on GKStateMachine specifically. Thanks for the suggestion πŸ™‚

    Reply
  4. Chris

    I really enjoyed this article. I always have trouble keeping delegates and protocols straight. It took me. few minutes to understand how everything was linked, but it makes sense now. Thanks!

    Reply
  5. Khawer Khaliq

    Hi, thanks for the article. Love your website.

    I have always felt that there isn’t enough interest in the Swift community in the GoF Design Patterns, which is a shame because a number of these patterns are still very useful and relevant. Inspired by your article, I did some work on implementing the State pattern in a more efficient and flexible way using some of the unique feature of Swift. I used the findings successfully in a project I was working on and just published an article on the subject:
    https://khawerkhaliq.com/blog/swift-design-patterns-state-pattern/

    Do check it out if you can. Thanks!

    Reply
    1. Dejan Agostini Post author

      Hi Khawer,
      Thanks for reading the blog and thanks for sharing your article. Very happy to see people taking interest in GoF πŸ™‚ The article is a bit long, it must have taken you ages to write. I’ll definitely check it out as soon as I find some time.
      Have a nice day πŸ™‚

      Reply
    1. Dejan Agostini Post author

      Hi Simon,

      Thanks πŸ™‚ And good catch, I’ve missed that. This was just a demo to illustrate the use of the pattern but you’re totally right. I’ll have to update it when I get a chance.

      Thanks and have a nice day πŸ™‚
      Dejan.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.