I've been tinkering with Cocoa for a few months now, and am trying to add undo/redo support to a strictly-for-learning-purposes Cocoa app I'm writing that lets you adjust iTunes track metadata. Thanks to NSUndoManager's prepareWithInvocationTarget:
method, I have the basics in place — you can undo/redo changes to the Play Counts and Last Played Dates of selected tracks, for example. (I'm using appscript-objc to get/set the iTunes track data.)
However as updating a large number of iTunes tracks can take a bit of time, I'd like to give the user the ability to cancel an undo/redo operation while it's in progress, but I'm not seeing an obvious mechanism to accomplish this with NSUndoManager. How would I go about doing this?
Edit:
To clarify, having thought about this a little more, I guess what I'm really after is a way to manipulate the undo/redo stacks so that I avoid the "inconsistent state" that Rob Napier mentions in his answer.
So, in response to an undo operation that failed without making any changes (say, before invoking the Undo, the user had opened iTunes' Preferences window, which blocks Apple Events), the undo operation could remain at the top of the undo stack, and the redo stack would be left unchanged. If the operation was cancelled or failed midstream, then I'd like to push onto the redo stack an operation that reverses the changes that went through (if any) and have on top of the undo stack an operation that applies the changes that didn't succeed. I suppose that effectively splitting the operation between the undo and redo stacks could invite user confusion, but it seems to be the most forgiving way of dealing with the issue.
I suspect the answer to this could be one of "Write your own damn Undo Manager", "Your Undo operations shouldn't be able to fail" or "You're overcomplicating this unnecessarily", but I'm curious. :)