當我們犯錯的時候,系統給了我們犯錯悔改的機會, 系統提供了讓我們回覆或者重做的API---NSUndoManager.
NSUndoManager的基本原理是其中有兩個棧---取消操作的棧和重做操作的棧,棧裏面裝的是NSInvocation對象。當執行一些特定操作後,在取消棧中壓入NSInvocation,其中封裝了消息的消息接受者,方法和參數等。當取消操作時,執行取消棧上棧頂的NSInvocation的消息, 重做的棧裏面會壓入重做的NSInvocation對象。這樣就通過兩個棧和NSInvocation,實現取消操作和重做操作。
例子:有一個TapMe按鈕,點擊後數字加1,Undo按鈕執行取消操作,Redo按鈕執行重做操作,ClearActions執行清除棧的操作。
@interface ViewController ()
{
IBOutlet UILabel *mLabel; //顯示的按鈕
IBOutlet UIButton *redoButton; //重做的按鈕
IBOutlet UIButton *undoButton; //取消的按鈕
IBOutlet UIButton *clearButton; //清除的按鈕
int number; //總共的點擊次數
NSUndoManager *undoManager;
}
- (IBAction)redoTapped:(id)sender;
- (IBAction)tapMeTapped:(id)sender;
- (IBAction)undoTapped:(id)sender;
- (IBAction)clearTapped:(id)sender;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
undoManager = [[NSUndoManager alloc] init];
redoButton.hidden = YES;
undoButton.hidden = YES;
}
//點擊按鈕點擊
- (IBAction)tapMeTapped:(id)sender
{
[self addNumber];
}
- (void)addNumber
{
number ++;
//一個取消操作的NSInvocation對象在Undo棧壓棧---包括取消操作的對象和方法
[[undoManager prepareWithInvocationTarget:self] subNumber];
mLabel.text = [NSString stringWithFormat:@"有效點擊數爲%d",number];
[self refreshpage];
}
- (void)subNumber
{
number --;
//一個重新操作的NSInvocation對象在Redo棧壓棧---包括重新操作的對象和方法
[[undoManager prepareWithInvocationTarget:self] addNumber];
mLabel.text = [NSString stringWithFormat:@"有效點擊數爲%d",number];
[self refreshpage];
}
//重做操作
- (IBAction)redoTapped:(id)sender
{
[undoManager redo]; //Redo棧的Invocation被調用,並被彈出棧
}
//取消操作
- (IBAction)undoTapped:(id)sender
{
[undoManager undo]; //Undo棧的Invocation被調用,並被彈出棧
}
//clearAction按鈕被點擊
- (IBAction)clearTapped:(id)sender
{
[undoManager removeAllActions]; //兩個棧裏面的所有NSInvocation對象都被彈出清空
[self refreshpage];
}
- (void)refreshpage
{
undoButton.hidden = !undoManager.canUndo;
redoButton.hidden = !undoManager.canRedo;
}