3

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.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Subcreation
  • 1,353
  • 12
  • 26

1 Answers1

3

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)
}
Subcreation
  • 1,353
  • 12
  • 26
  • For me, it is `null` even after calling `becomeFirstResponder()` in `viewDidLoad()`. I am using Swift 5.1. Is there anything else that I need to keep in mind? I am listening to keyDown events in the same ViewController as well. And, I am *not* setting any action name. I hope these aren't causing the issue. – Ram Patra Apr 28 '20 at 11:04
  • This doesn't work for me either. `undoManager` is still `nil` – Alex May 10 '20 at 21:52