Cocoa Application Competencies for iOS

Undo manager

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

The NSUndoManager class gives you two ways to register undo operations:

For invocation-based registration, call prepareWithInvocationTarget:, passing in a NSInvocation object 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 undo or redo message to a NSUndoManager object.

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 (UIResponder or 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.