1

I have been stuck on this for a while. There are similar problems on stack overflow but none have led me to the solution I'm looking for. Also, can't seem to find any info in the official docs.

I am building a macOS application programatically. I have set up my own menu bar programmatically. I have an NSTextView and some NSTextfields which I have set up perfectly fine as subviews of another view. Everything working except the undo/redo functionality, which I have read is supported in these classes. I have myTextView.allowsUndo = true but it just does not work. Why is the undo manager not automatically doing stuff like I'm pretty sure it is supposed to?

Here is the relevant part of my menu code:

let editMenu = NSMenuItem()
editMenu.submenu = NSMenu(title: "Edit")
editMenu.submenu?.items = [
NSMenuItem(title: "Undo", action: #selector(UndoManager.undo), keyEquivalent: "z"),
NSMenuItem(title: "Redo", action: #selector(UndoManager.redo), keyEquivalent: "Z")
]

I'm thinking it might be something to do with linking the UndoManager to my window or the textfields and views? I want to set this up without having to make my own undo manager functions.

Relstoch
  • 21
  • 4
  • `NSTextView` and `NSTextField` both support undo and redo operations without your interaction UNLESS you are using SwiftUI. – El Tomato May 02 '21 at 00:34

1 Answers1

3

This works on my system:

// **** Edit Menu **** //
 let editMenu = NSMenuItem()
  editMenu.submenu = NSMenu(title: "Edit")
  editMenu.submenu?.addItem(withTitle: "Undo", action: Selector(("undo:")), keyEquivalent: "z")
  editMenu.submenu?.addItem(withTitle: "Redo", action: Selector(("redo:")), keyEquivalent: "Z")
  editMenu.submenu?.addItem(.separator())
  editMenu.submenu?.addItem(withTitle: "Cut", action: #selector(NSText.cut(_:)), keyEquivalent: "x")
  editMenu.submenu?.addItem(withTitle: "Copy", action: #selector(NSText.copy(_:)), keyEquivalent: "c")
  editMenu.submenu?.addItem(withTitle: "Paste", action: #selector(NSText.paste(_:)), keyEquivalent: "v")
  editMenu.submenu?.addItem(withTitle: "Select All", action: #selector(NSText.selectAll(_:)), keyEquivalent: "a")

Make sure you have the other edit menu items. In order to 'undo' something you have to 'do' it to start with. Also need to set txtView.allowsUndo = true as you have correctly done. Please note that Selector(someString) is different from #selector(). It's actually old swift syntax, but it still works. Swift relies on objc for selectors.

apodidae
  • 1,988
  • 2
  • 5
  • 9
  • Please explain why your code does work and the code in the question doesn't. – Willeke May 02 '21 at 08:44
  • @Willeke I think it has something to do with the fact that swift handles selectors differently (or not at all) and we have to fall back to objc to get the job done. Thanks for docking my answer. – apodidae May 02 '21 at 11:26
  • Thanks so much @apodidae your solution works perfectly. Wow, I don't think I ever would have got that on my own. – Relstoch May 02 '21 at 16:20
  • @Relstoch. If my answer works for you, could you please check it as being the correct answer? I seem to lose points every time I try to help someone in this forum. Thanks. – apodidae May 02 '21 at 16:56
  • I did get a warning using the `Selector(someString)` which xcode can fix for you by adding an extra set of parentheses around `someString`. I have also been made aware of another question which solves this in another way using an `@objc protocol` to link the undo function. – Relstoch May 03 '21 at 01:32
  • Go ahead and put the parentheses back in. They were in the code before I posted it, but I removed them thinking that they were redundant and not necessary. The editor that I use didn't complain unless there was some other error, then I additionally got the error that you mentioned. You stated that you didn't want to have to write your own undo method so I thought @objc function would be unacceptable to you. – apodidae May 03 '21 at 02:06
  • Thanks for showing us how to use @objc protocol (reference at top of page). I can confirm that it also works and will obviate deprecated code. – apodidae May 03 '21 at 04:27