I am trying to implement undo/redo in my model. So I made my model class a subclass of NSResponder
, and then implemented the following:
note: this code is edited based on more research after comments
func setAnnotations(_ newAnnotations: [Annotation]) {
let currentAnnotations = self.annotations
self.undoManager.registerUndo(withTarget: self, handler: { (selfTarget) in
selfTarget.setAnnotations(currentAnnotations)
})
self.annotations = newAnnotations
}
Annotation
is a struct.
The code inside the closure never gets executed. Initially I noticed that undoManager
is nil
, but then I found this snippet:
private let _undoManager = UndoManager()
override var undoManager: UndoManager {
return _undoManager
}
Now undoManager
is no longer nil, but the code inside the closure still doesn't get executed.
What am I missing here?
I can't reproduce any issue now that you've made your undo register code make sense. Here is the entire code of a test app (I don't know what an Annotation is so I just used String):
import Cocoa
class MyResponder : NSResponder {
private let _undoManager = UndoManager()
override var undoManager: UndoManager {
return _undoManager
}
typealias Annotation = String
var annotations = ["hello"]
func setAnnotations(_ newAnnotations: [Annotation]) {
let currentAnnotations = self.annotations
self.undoManager.registerUndo(withTarget: self, handler: { (selfTarget) in
selfTarget.setAnnotations(currentAnnotations)
})
self.annotations = newAnnotations
}
}
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
let myResponder = MyResponder()
@IBOutlet weak var window: NSWindow!
func applicationDidFinishLaunching(_ aNotification: Notification) {
print(self.myResponder.annotations)
self.myResponder.setAnnotations(["howdy"])
print(self.myResponder.annotations)
self.myResponder.undoManager.undo()
print(self.myResponder.annotations)
}
}
The output is:
["hello"]
["howdy"]
["hello"]
So Undo is working perfectly. If that's not happening for you, perhaps you are mismanaging your "model class" in some way.
By the way, a more correct to write your registration closure is this:
self.undoManager.registerUndo(withTarget: self, handler: {
[currentAnnotations = self.annotations] (selfTarget) in
selfTarget.setAnnotations(currentAnnotations)
})
This ensures that self.annotations
is not captured prematurely.