An undo manager is a framework object for recording changes to object state and later undoing those changes upon user request. The undo manager, which is an instance of the
NSUndoManager class, conducts both undo and redo operations. An undo operation reverts a change to a property of an object; a redo operation restores the original value if an undo operation has taken place. The ability to perform undo and redo operations is a valuable and differentiating feature of applications, especially those that allow users to change data extensively.
You obtain an undo manager through the
undoManager property of
UIResponder (iOS) or by calling the
undoManager method of
NSResponder (OS X). Every window of an application provides a default undo manager, although you can create private ones for specific contexts.
Undo and Redo Operations Send Messages to the Changed Object
You must register an undo operation with the undo manager. When the undo manager executes the operation, it sends a message composed from several components supplied in registration:
The object to receive the message. The receiving object is typically an object having a property whose value has changed.
The signature of the method to invoke. The signature often identifies a setter accessor method.
The argument of the message. The argument is typically the previous value of the property that has changed. For redo operations, the argument is the changed value.
An undo manager collects all undo operations that occur within a single cycle of a run loop such as the application’s main event loop; executing an undo operation reverts all changes that occurred during the cycle. When performing an undo operation, an undo manager saves the operations that were reverted so that users can redo what has been undone.
Undo and Redo Operations Are Put on Stacks
An undo manager stores undo and redo operations on first-in last-out stacks. When an application first registers an undo operation, the undo manager adds it to the undo stack. The redo stack, however, remains empty until the user requests an undo operation. When that happens, the undo manager uses the topmost group of operations on the undo stack to compose and send one or more messages to revert changes.
Since these operations again cause changes to one or more object’s state, the objects register new operations with the undo manager, this time in the reverse direction from the original operations. Because the undo manager is currently undoing changes, it records these operations as redo operations on the redo stack. Subsequent redo operations pull the operations off the redo stack, apply them to the objects, and push them back onto the undo stack. Because a new change to an object’s state invalidates the previous change, as soon as a new undo operation is registered, an undo manager clears the redo stack.
Operations Are Coalesced into Undo Groups
An undo manager collects undo and redo operations in groups that represent actions that are entirely revertible. A group typically identifies properties that are related in some way. It stores these groups of operations as items on the undo and redo stacks. Even a single action must be packaged as a group.
NSUndoManager normally creates undo groups automatically during a cycle of the run loop. The first time it is asked to record an undo operation in the cycle, it creates a new group. Then, at the end of the cycle, it closes the group. You can create additional, nested undo groups.
How to Register and Request Undo and Redo Operations
NSUndoManager class gives you two ways to register undo operations:
For simple registration, call
registerUndoWithTarget:selector:object:, which takes a target object, a selector, and a single argument.
For invocation-based registration, call
prepareWithInvocationTarget:, passing in a
NSInvocationobject that encapsulates the message to send for reverting changes. With this approach you can have any number and type of arguments.
You often call these methods in the accessor method for a property of an object that is being changed. To request an undo or redo operation, send
redo message to a
The Undo Manager and the Responder Chain
The responder chain plays an important role in undo management, especially when more than the default undo manager is in play. The responder class in either the UIKit or AppKit frameworks (
NSResponder) declares the
undoManager property and
undoManagermethod, respectively. When an application receives an undo event, the responder class starts with the first responder and from there goes up the responder chain looking for an
NSUndoManager object (through the
undoManager property or method). If the end of the responder chain is reached, the window object creates and returns the default undo manager.
If you want an undo manager for a specific context in addition to the default undo manager, your responder subclass can implement the
undoManager property or method to create and return one. The responder subclass is often a custom view but it can also be, on iOS, a view controller (which must ensure that it becomes first responder). In OS X, the delegate of a window object can implement the
windowWillReturnUndoManager: to return an undo manager.
The User Interface for Requesting Undo and Redo
Users request undo and redo operations in OS X and iOS in different ways. In a Mac app, the user chooses an Undo or Redo menu command from the Edit menu. In an iOS application, the user shakes the device. For a shaking motion to function as command, the
applicationSupportsShakeToEdit property of
UIApplication must be set to
YES and there must be an undo manager in an appropriate state. If these conditions apply, the application displays an alert view with buttons for undo and redo. In both iOS and OS X, you can give specific action names to undo and redo commands—for example, Undo Color Change.