Components of the memento pattern

The memento pattern requires the implementation of three distinct entities:

Memento, in other languages, may be implemented as an opaque box so the state can't be mutated. In Swift, we can leverage structs, their immutability, and the fact they are passed by value and not reference. It is critical that different Memento objects do not share memory.

Let's start by implementing a generic memento pattern. Thanks to Swift and its powerful protocols, we can leverage associated types in order to implement the memento pattern. 

Let's start with the first important type, Originator:

protocol Originator {
associatedtype MementoType

func createMemento() -> MementoType
mutating
func setMemento(_ memento: MementoType)
}

Originator has just two responsibilities, to create mementos for CareTaker and restore its state using the setMemento method. Note that the state of Originator should be fully restorable through the Memento.

Now, let's have a look at CareTaker:

protocol CareTaker {
associatedtype OriginatorType: Originator
var originator: OriginatorType { get set }

var mementos: [OriginatorType.MementoType] { get set }
mutating func save()
mutating func restore()
}

CareTaker has a reference to the Originator as it should be able to get and restore Memento objects from it.

We'll use the associated type again to store the Memento objects into an array. This will let us push and pop states easily. With the help of extensions, it is even possible to implement the save() and restore() methods:

extension CareTaker {
mutating func save() {
mementos.append(originator.createMemento())
}

mutating func restore() {
guard let memento = mementos.popLast() else { return }
originator.setMemento(memento)
}
}

With those two protocols in place, we can get started with a more complex example that involves saving the state of a large object.