[ios2]NSUndoManager 【转】

在Cocoa中使用NSUndoManager可以很方便的完成撤销操作。NSUndoManager会记录下修改、撤销操作的消息。这个机制使用两个NSInvocation对象栈。

     NSInvocation会把消息(选择器和接受者及参数)包装成一个对象,这个对象就是NSInvocation的实例。当一个对象收到它不理解的消 息时,消息发送机制会在报出错误前检查该对象是否实现了forwardInvocation这个方法。如果实现了,就会将消息打包成 NSInvocation对象,然后调用forwardInvocation方法。


    1) NSUndoManager工作原理
    当进行操作时,控制器会添加一个该操作的逆操作的invocation到Undo栈中。当进行Undo操作时,Undo操作的逆操作会倍添加到Redo栈中,就这样利用Undo和Redo两个堆栈巧妙的实现撤销操作。

    这里需要注意的是,堆栈中存放的都是NSInvocation实例。


    2)示例
    假设在我们的程序中有walkLeft以及这个方法的逆方法walkRight,我们可以这样来实现撤销功能。
- (void) walkLeft
{
    position = position + 10;
    [[undoManager prepareWithInvocationTarget:self] walkRight];
    [self showTheChangesToThePostion];
}

    prepareWithInvocationTarget:方法记录了target并返回UndoManager,然后UndoManager重载了 forwardInvocation方法,也就将walkRight方法的Invocation添加到undo栈中了。
   
- (void) walkRight
{
    position = position - 10;
    [[undoManager prepareWithInvocationTarget:self] walkLeft];
    [self showTheChangesToThePostion];

}


    UndoManager还可以设置撤销菜单动作的名称:
    [undoManager setActionName:@"Insert"];
//===一下是我在源代码网站里复制过来的代码,有学习价值====//
- (NSInvocation *) drawScribbleInvocation
{
  NSMethodSignature *executeMethodSignature = [scribble_
                                               methodSignatureForSelector:
                                               @selector(addMark:
                                                         shouldAddToPreviousMark:)];
  NSInvocation *drawInvocation = [NSInvocation
                                  invocationWithMethodSignature:
                                  executeMethodSignature];
  [drawInvocation setTarget:scribble_];
  [drawInvocation setSelector:@selector(addMark:shouldAddToPreviousMark:)];
  BOOL attachToPreviousMark = NO;
  [drawInvocation setArgument:&attachToPreviousMark atIndex:3];
 
  return drawInvocation;
}

- (NSInvocation *) undrawScribbleInvocation
{
  NSMethodSignature *unexecuteMethodSignature = [scribble_
                                                 methodSignatureForSelector:
                                                 @selector(removeMark:)];
  NSInvocation *undrawInvocation = [NSInvocation
                                    invocationWithMethodSignature:
                                    unexecuteMethodSignature];
  [undrawInvocation setTarget:scribble_];
  [undrawInvocation setSelector:@selector(removeMark:)];
 
  return undrawInvocation;
}

调用:
[self executeInvocation:drawInvocation withUndoInvocation:undrawInvocation];
 
- (void) executeInvocation:(NSInvocation *)invocation
        withUndoInvocation:(NSInvocation *)undoInvocation
{
  [invocation retainArguments];

  [[self.undoManager prepareWithInvocationTarget:self]
   unexecuteInvocation:undoInvocation
   withRedoInvocation:invocation];
 
  [invocation invoke];
}

- (void) unexecuteInvocation:(NSInvocation *)invocation
          withRedoInvocation:(NSInvocation *)redoInvocation
{  
  [[self.undoManager prepareWithInvocationTarget:self]
   executeInvocation:redoInvocation
   withUndoInvocation:invocation];
 
  [invocation invoke];
}

 
 
posted @ 2013-06-06 08:24  金建彤  阅读(446)  评论(0编辑  收藏  举报