How can I integrate my own text changes into UITextView's undo manager?

40 views Asked by At

I have an app that uses UITextView for some text editing. I have some custom operations I can do on the text that I want to be able to undo, and I'm representing those operations in a way that plugs into NSUndoManager nicely. For example, if I have a button that appends an emoji to the text, it looks something like this:

func addEmoji() {
  let inserting = NSAttributedString(string: "")
  self.textStorage.append(inserting)

  let len = inserting.length
  let range = NSRange(location: self.textStorage.length - len, length: len)
  self.undoManager?.registerUndo(withTarget: self, handler: { view in 
    view.textStorage.deleteCharacters(in: range)
  }
}

My goal is something like this:

  1. Type some text
  2. Press the emoji button to add the emoji
  3. Trigger undo (via gesture or keyboard shortcut) and the emoji is removed
  4. Trigger undo again and the typing from step 1 is reversed

If I just type and then trigger undo, the typing is reversed as you'd expect. And if I just add the emoji and trigger undo, the emoji is removed. But if I do the sequence above, step 3 works but step 4 doesn't. The emoji is removed but the typing isn't reversed.

Notably, if step 3 only changes attributes of the text, like applying a strikethrough to a selection, then the full undo chain works. I can type, apply strikethrough, undo strikethrough, and undo typing.

It's almost as if changing the text invalidates the undo manager's previous operations?

How do I insert my own changes into UITextView's NSUndoManager without invalidating its chain of other operations?

Update: Sample code here.

0

There are 0 answers