< Previous PageNext Page > Hide TOC

Registering Undo Operations

To add an undo operation to the undo stack, you must register it with the object that performs the undo operation. NSUndoManager supports two ways to register undo operations: one based on a simple selector with a single object argument, and one based on a general NSInvocation (which allows any number and type of arguments). In the first type of operation, when an object changes, the object itself (or another object acting on its behalf) registers the change with the undo manager, passing an argument that holds the attributes of the object prior to the change. (This argument is frequently an NSDictionary object, but it can be any object.) Performing the undo then involves resetting the object with these attributes. Invocation-based undo is useful for undoing specific state-changing methods, such as a setFont:color: method.

In most applications a single instance of NSUndoManager belongs to an object that contains or manages other objects. This is particularly the case with document-based applications, where each NSDocument object is responsible for all undo and redo operations for a document. An object such as this is often called the NSUndoManager’s client. Each client object has its own NSUndoManager. The client claims exclusive right to alter its undoable objects so that it can record undo operations for all changes. In the specific case of documents, this scheme keeps each pair of undo and redo stacks separate so that when an undo is performed, it applies to the focal document in the application (typically the one displayed in the key window). It also relieves the individual objects in a document from having to know the identity of their NSUndoManager or from having to track changes to themselves.

However, an object that is changed can have its own NSUndoManager and perform its own undo and redo operations. For example, you could have a custom view that displays images dragged into it; with each successful drag operation, it registers a new undo group. If the view is then selected (that is, made first responder) and the Undo command applied, the previously displayed image would be redisplayed.

Contents:

Simple Undo
Invocation-Based Undo


Simple Undo

To record a simple undo operation, you need only invoke registerUndoWithTarget:selector:object:, giving the object to be sent the undo operation selector, the selector to invoke, and an argument to pass with that message. The target object is usually not the actual object whose state is changing; instead, it is the client object, a document or container that holds many undoable objects. The argument is an object that captures the state of the object before the change is made. Here is an Objective-C method from the Draw example application (DrawDocument.m):

- (void)setGridVisible:(NSNumber *)flag {
    BOOL flagValue = [flag boolValue];
    if (gvFlags.showGrid != flagValue) {
        NSNumber *currentValue = [NSNumber numberWithBool:gvFlags.showGrid];
        gvFlags.showGrid = flagValue;
        if (flagValue)
            [graphicView resetGUP];
        [graphicView cache:[graphicView bounds]];
        [undoManager registerUndoWithTarget:self
                selector:@selector(setGridVisible:)
                object:currentValue];
        [undoManager setActionName:GRID_OP];
    }

If the user chooses Undo, setGridVisible: is invoked with the previous value.

Invocation-Based Undo

For other changes involving specific methods or arguments that are not objects, you can use invocation-based undo, which records an actual message to revert the target object’s state. As with simple undo, you record a message that reverts the object to its state before the change. However, in this case you do so by sending the message directly to the NSUndoManager, after preparing it with a special message to note the target, as in this Objective-C example:

[[myUndoManager prepareWithInvocationTarget:drawObject]
    setFont:[drawObject font] color:[drawObject color]];
[drawObject setFont:newFont color:newColor];

The prepareWithInvocationTarget: method records the argument as the target of the undo operation about to be established. Following this, you send the message that reverts the target’s state—in this case, setFont:color:. Because NSUndoManager does not respond to this method, forwardInvocation: is invoked, which NSUndoManager implements to record the NSInvocation containing the target, selector, and all arguments. Performing undo thus results in drawObject being sent a setFont:color: message with the old values.



< Previous PageNext Page > Hide TOC


© 2002 Apple Computer, Inc. All Rights Reserved. (Last updated: 2002-11-12)


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.