Memento🏆 Design Pattern — SwiftUI

Kiran Sarella
2 min readMar 4, 2024

--

a doc snapshots example

“..making snapshots of an object’s state and restoring it in future.. ”

Intent ♖♞

Without knowing the object’s internal state, have to capture and save the state externally, so that the object can be restored to this state later.

DocEditor Example 📝

Source Code: https://github.com/KiranSarella/Memento-SwiftUI

Participants ⛄︎☃︎

Internal State, Memento, Originator, Caretaker

Internal State 💎

Doc contain internal state, in this case only content (in other usecases, the internal state might be more complex)

struct DocCurrentState: Hashable {
var content: String
}

Memento 🎁

Memento have two interfaces,

☞ One is private (wide) interface, only the memento creator class (Originator) can access this interface.

private protocol DocSnapshot {
var state: DocCurrentState { set get }
}

☞ Other is public (narrow) interface, this can be seen by those who maintains and stores the collection of mementos.

protocol Snapshot {
var id: UUID { get }
var name: String { set get }
}

below is the memento, which is confirmed to both `public` and `private` interfaces.

private struct Memento: Snapshot, DocSnapshot {
var id: UUID
var name: String = ""
var state: DocCurrentState
}

Originator 🧞‍♂️

→ create memento

Creates a memento when requested.

func createSnapshot(for state: DocCurrentState) -> Snapshot {
Memento(id: UUID(), state: state)
}

← restore memento

Only this class has the access to the private (wide) interface. So, only this has to retrieve the internal state from the given memento.

func getDocState(for anyMemento: Snapshot) -> DocCurrentState? {
guard let memento = anyMemento as? DocSnapshot else { return nil }
return memento.state
}

‼️Originator is not responsible for maintaining the history of mementos.

Caretaker 🚛

  • Responsible for the memento’s safe keeping.
  • In our case, `DocEditor` maintains all the snapshots.
  • Never operates on or examines the contents of a memento.
class DocEditorBusiness {

func saveDocCurrentState(for content: String) -> Snapshot {
let name = "Snapshot \(snapshotCount + 1)"
var snapshot = docBusiness.prepareSnapshot(for: content)
snapshot.name = name
snapshot.state //⚠️ no access
storage.saveSnapshot(snapshot)
return snapshot
}

func restoreDocToOldState(snapshot: Snapshot) -> String? {
docBusiness.restore(snapshot: snapshot)
}

func getAllSnapshots() -> [Snapshot] {
storage.getAllSnanshots()
}

}

--

--

No responses yet