带块的NSUndoManager

时间:2012-07-18 04:29:26

标签: objective-c cocoa objective-c-blocks block nsundomanager

在我希望支持块的所有事情中,NSUndoManager好奇地似乎没有这样做。是否存在一些固有的原因,或者苹果公司是否根本没有将这一点API现代化?

特别是我想在NSObject上定义一个方法,

- (void)performBlock {
    void (^block)(void) = (id)self;
    block();
}

为了能够打电话,

[[undoManager prepareWithInvocationTarget:^{
    NSLog( @"hello world" );
}] performBlock];

我错过了什么吗?这有什么不对吗?

(受到2009年Mike Ash article的启发,建议定义块上的方法。我也在那里发表评论。)

1 个答案:

答案 0 :(得分:2)

我认为迈克的主要论点是它使代码难以阅读,而不是这个想法存在根本问题。

但是,我发现你写的内容存在一些问题。首先,你在NSObject上添加了一个类别方法,但是如果你在一个不是块的对象上调用它,它就会崩溃。也许有一种方法可以解决这个问题,比如让performBlock方法在非块上调用时什么都不做,或者至少在崩溃之前记录错误。我不完全是这样的。

此外,块从堆栈开始,因此您需要先复制它们,然后再将它们传递给一个方法,以便稍后执行它们。编写的方法可以解决这个问题。据推测,-[NSUndoManager prepareWithInvocationTarget:]不会复制传入的目标。因此,您需要自己复制该块(使用-copyBlock_copy()),然后再将其传入:

void (^block)(void) = [^{
    NSLog(@"hello world");
} copy];

[[undoManager prepareWithInvocationTarget:block] performBlock];
[block release];

至少在ARC的早期版本中,这仍然是一个问题,因为块被传递到期望id的方法中(如Mike Ash的ARC article的块部分所述)。也许它已被修复?我不指望它......