views:

160

answers:

2

Hi, I have been trying to design the Undo/Redo functionality in one of my app using NSUndoManager class and seeing some design difficulties. In my app, I just have one method

-(IBAction) addLastBall:(Ball *)ball

So, when a user chooses a button in the UI, I add a ball object to my array list. However, I don't have any action button to remove a ball, this is the design of the UI workflow and can't be changed. So, to implement a undo I called the following piece of code inside the addLastBall method

[undoManager registerUndoWithTarget:self selector:@selector(removeBall:) object:ball];

After doing this, removeBall method gets called with the ball object when the user tried to perform the undo. All is good for now. But, I am not sure how to handle the redo part now, when the user tries to redo, I am not sure which method would get called, because I need to add the ball object the user just removed using the undo operation. Any insights would be very helpful.

Thanks so much.

A: 

No method get's called. The NSUndoManager simply saves the reverse of the undo operation (redo), that will be done, if the user choses redo.

It's all implemented in NSUndoManager, so you don't have to worry about it. If you want your method to be called on redo, you should think about creating your own undo manager, but I wouldn't advice you to. It can get very complicated and besides, the NSUndoManager takes care of everything perfectly.

tadej5553
+1  A: 

A redo simply performs the undo actions registered while the corresponding undo was executing. Therefore, the most straightforward solution is to simply to register an undo action in the removeBall: method.

- (void)removeBall:(Ball *)ball {
    [undoManager registerUndoWithTarget:self 
                               selector:@selector(addLastBall:)
                                 object:ball];
    ...
}

Note that it is sometimes clearer to useprepareWithInvocationTarget: to register undo actions:

[[undoManager prepareWithInvocationTarget:self] addLastBall:ball];

By the way, be sure to keep the retain count of the ball above zero in the removeBall: method — the undo manager will not retain the ball for you, and if it gets deallocated, then undoing the remove will crash.

Fnord