Resetting the Undo/Redo Stack after Applying an Undo/Redo Action in iOS

If you are developing iOS applications and are not using NSUndoManager, you should be.  The class provides a very solid implementation for enabling undo/redo functionality within an iOS application.

However, when I first wired the class into a project, I quickly noticed that changing a value after navigating backward into the undo stack did not clear the now-downstream, previously-applied undo stack operations.  Which is to say, if I undid an edit and then changed the value of the “undone” field, I could redo to the value prior to the undo.  Which, much like that last sentence, is very confusing and hard to follow.

Most undo/redo implementations assume that applying a change after navigating backwards in the undo stack should invalidate the forward operations within the stack.  So while I was surprised that wasn’t happening right out of the box with NSUndoManager, I assumed it was capable of the behavior (i.e. I must be doing something wrong).

And I was correct.  Straight out of the box, NSUndoManager assumes that all undo operations are non-discardable, which is to say, it will preserve them even when the state of the class hints that the operation may no longer be valid.  To enable the functionality of having the traversed undo operations removed from the redo stack once a modification is made to the “undone” data value, I simply had to indicate that the applied undo operations should be treated as “discardable“.

A very straightforward, and possibly overly-aggressive, way of doing this would be to subclass the NSUndoManager and override prepareWithInvocationTarget as so:

– (id) prepareWithInvocationTarget:(id)target
// This ensures that the redo stack is reset if the user
// edits a field after moving back in the undo stack.
[self setActionIsDiscardable:true];
return [super prepareWithInvocationTarget:target];

As is often the case with software development, your project likely has some characteristics that are very specific to your application, so the above code likely is not be a perfect fit to your problem. However, if you’re looking for a way to reset the redo stack of NSUndoManager, the above code should provide some guidance on how to develop a solution that fits your needs.