I want to implement undo/redo operations in my app. The undo/redo actions need to be recorded for every document rather than at UIViewController level. So I will need to put UndoManager in the class implementing custom document. But one of the requirement is that undo/redo should be possible even when the app is restarted, which means UndoManager must be persistent. How do we make UndoManager state persistent?
As far as I know, The UndoManager does not directly relate to your data model, hence does not directly relate to your app state - i.e the data model state. It merely allows you to register some actions that will alter your data model in an undo/redo fashion. To achieve persistency, while using the UndoManager, you will have to use some persistent store (a DB like Core Data or Realm, or for a very simple state you can use UserDefaults). You will have to make the actions you register with your UndoManager to update the persistent store you choose to use. In addition, you will have to somehow keep track of the changes in the DB so you can restore and register them back between application launches.
An example I found online that describes the Undo/Redo actions registrations - taken from this example - https://medium.com/flawless-app-stories/undomanager-in-swift-5-with-simple-example-8c791e231b87
//MARK:- Add/Remove Student : Undo/Redo Actions
// Register inverse Actions that automatically performs
extension StudentsListViewController {
func addNewStudentUndoActionRegister(at index: Int){
self.undoManager?.registerUndo(withTarget: self, handler: { (selfTarget) in
selfTarget.removeNewStudent(at: index)
selfTarget.removeNewStudentUndoActionRegister(at: index)
})
}
func removeNewStudentUndoActionRegister(at index: Int){
self.undoManager?.registerUndo(withTarget: self, handler: { (selfTarget) in
selfTarget.addNewStudent(at: index)
selfTarget.addNewStudentUndoActionRegister(at: index)
})
}
}
As you can see, the actions will just change the state and the UndoManager does not keep track of the state, just the actions...
Some personal opinions: For complex logic and state, I personally like to use some state management frameworks like Redux (or the Swift equivalent ReSwift), in this case, I can easily create an Undo/Redo actions. And you can easily keep a record of the state along the application lifecycle, and record it to a persistent store, for example, make your state Codable and keep a stack of it in storage. It kind of bits the purpose of using the UndoManager - but as far as I know you cannot keep the registered actions to disk.