Search code examples
macosswiftnsundomanager

How do I access the undoManager for my Mac OS app in swift?


I am simply trying to get undo working for the actions a user performs in my app. By default, any text editing the user does has the benefit of undo, but any actions that are done otherwise (from my code) does not.

I can see the documentation explains that I need to get an instance of NSUndoManager and call registerUndoWithTarget, but I am stumped with the first step: getting the undoManager from within my ViewController. Since ViewController is a UIResponder, I tried this:

if let undoManager = self.undoManager {
            undoManager.registerUndoWithTarget(self, selector: Selector("removeLatestEntry:"), object: "test")
        }

Since that binding returns nil, I thought maybe the ViewController doesn't have the undoManager, so I looked for it in the window:

if let window = NSApplication.sharedApplication().mainWindow {
        if let undoManager = window.undoManager {
            undoManager.registerUndoWithTarget(self, selector: Selector("removeLatestEntry:"), object: "test")
        }
    }

Alas, the window binding also returns nil. Sorry, I am very new to this. Can anyone point me in the right direction? Am I supposed to implement my own undoManager or something? There is clearly an undoManager somewhere because anything a user does manually in my textField is getting undo behavior. It seems like this would be a singleton that I could access easily from a ViewController.

-- Edit: BTW, the code above was placed in viewDidLoad and removeLatestEntry is just a function in my ViewController that takes a string and prints it at this point.


Solution

  • To use undoManager, the ViewController needs to be first responder. So:

    override func viewDidLoad() {
        super.viewDidLoad()
    
        // Do any additional setup after loading the view.
    
        becomeFirstResponder()
    }
    

    Then, from wherever your action is defined that needs to be reversed, you register your undo and pass it whatever it needs to undo that action. So in my case:

    func addEntry(activity: String) {
        // some other stuff…
        undoManager!.registerUndoWithTarget(self, selector: Selector("removeLatestEntry:"), object: activity)
    }