`NSUndoManager` provides an awesomely simple method of undoing, that handles groups, menus and unlimited undo/redo. `prepareWithInvocationTarget` converts the undo manager into a proxy for the target, which records the next method call as an undo step. The method you call on undo manager should then be the step to undo what is currently being done. This is all you need do! It means that setter methods with undo can be as simple as this:

– (void)setSize:(float)newSize
{
[[undoManager prepareWithInvocationTarget:self] setSize:size]; // call to undo current set
size = newSize;
}

The problem

Live user interfaces are much more usable. An example is a slider that updates the size of an object as you drag. Unfortunately live updating the object like this involves setting the size for every twitch of the mouse. This quickly stacks up hundreds of undo actions. Not only do these take up lots of memory, they cause `NSUndoManager` to slow down and your whole app takes a hit. One solution is to use a undo queue as suggested by Mark Dalrymple Undology 101. But this requires a restructuring of code that is both tedious and obsfucating.

My Solution

My solution to this problem is to provide a simple sub-class of `NSUndoManager` that handles this case without any change to your code structure. I introduce two new methods `prepareWithSkippableInvocationTarget` and `registerSkippableUndoWithTarget` that work in the same way as `prepareWithInvocationTarget` and `registerUndoWithTarget` except that they skip invocations that are duplicates of the previous undo call. In this way none of the existing functionality of `NSUndoManager` is changed, and it is extended to provide duplicate removal for skippable methods.

– (void)setSize:(float)newSize
{
[[undoManager prepareWithSkippableInvocationTarget:self] setSize:size];
size = newSize;
}

That’s it!

Warnings

* This and the previous solution can only be used on non-sideffect-non-destructive (skippable) methods.
* If actions are not handled over a single run loop cycle, there is going to be odd coalescing. (`NSUndoManager` groups automatically over a run loop cycle) If this is the case just use a notification queue or some extra logic to handle the special case using the standard method calls to the `NSUndoManager`.

TDUndoManager

The source code: TDUndoManager.zip
A test app and code: TDUndoManagerTest.zip (69kB)