The Undo Manager

Undo is provided through an instance of NSUndoManager, which basically just maintains a stack of undoable actions, along with a secondary stack of redoable actions. The goal in general is to work with the NSUndoManager so as to handle both Undo and Redo in the standard manner: when the user chooses to undo the most recent action, the action at the top of the Undo stack is popped off and reversed and is pushed onto the top of the Redo stack.

To illustrate, I’ll use an artificially simple app in which the user can drag a small square around the screen. We’ll start with an instance of a UIView subclass, MyView, to which has been attached a UIPanGestureRecognizer to make it draggable, as described in Chapter 18. The gesture recognizer’s action target is the MyView instance itself:

- (void) dragging: (UIPanGestureRecognizer*) p {
    if (p.state == UIGestureRecognizerStateBegan ||
            p.state == UIGestureRecognizerStateChanged) {
        CGPoint delta = [p translationInView: self.superview];
        CGPoint c = self.center;
        c.x += delta.x; c.y += delta.y;
        self.center = c;
        [p setTranslation: CGPointZero inView: self.superview];
    }
}

To make dragging of this view undoable, we need an NSUndoManager instance. Let’s store this in an instance variable of MyView itself, accessible through a property, undoer.

There are two ways to register an action as undoable. The one we’ll use involves the NSUndoManager method registerUndoWithTarget:selector:object:. This method uses a target–action architecture: you ...

Get Programming iOS 6, 3rd Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.