Getting Ready For 3.0: Undo/Redo
The copy-and-paste demo in Apple’s public iPhone 3.0 preview event demonstrated “shake to undo” and “shake to redo” capabilities at around the hour-and-six-minute mark in the presentation video.
While we can’t know with certainty what Apple’s plans for undo/redo on the iPhone will be until 3.0 leaves beta, we can infer some clues from their presentation:
The demo showed support for multiple undos/redos, just like on OS-X. Given the similarities between Cocoa Touch on the phone and Cocoa on OS-X, it’s seems reasonable to predict that the model for undo/redo capabilities will be similar.
OS-X’s undo/redo capabilities are provided by the
NSUndoManager class. The class, documented here, works by keeping a stack of messages that, if sent, would serially undo the last action, the penultimate action, and on back until arriving at the initial state.
Let’s use an example to illustrate how this works: our city, concerned with a perceived increase in the number of trucks plying our streets, has commissioned a census. City workers, siting in pairs on park benches around the community, will tally truck traffic using an iPhone app. See a truck, tap the button. Oops! Mistook that Subaru Forester for a truck? Shake to undo.
Internally, like all Objective-C based apps, we’re sending messages. Send a
addATruck message to move the ticker forward; send a
removeATruck message to move the ticker back.
So, in undo-manager terms: the
addATruck method, when called, should to add a
removeATruck message to the undo-manager’s stack. Specifically, undo-manager uses
NSInvocation objects, which are essentially messages saved for later sending, to accomplish our undoing.
Our particular example, of course, could easily be accommodated without an undo-manager using simple subtraction. However, the undo-manager simplifies more complex situations — e.g., expanding our sample app separate tallies by the number of axels.
Earlier I said that
NSUndoManager keeps a stack of undo actions. More precisely, there are actually two stacks: one for undoing actions and another for re-doing the same actions. When you undo some action the messages that originally made up that action are placed on the redo stack. Redo is, effectively, undoing an undo. Fortunately, as a programmer, all of this is handled by the undo-manager, so you don’t have to worry about the details.
Conceptually, that about covers it. For some sample code and a more detailed tutorial, have a look at the NSUndoManager Tutorial at CocoaDev.