3

在我期望支持块的所有事情中,奇怪的是,NSUndoManager 似乎并没有这样做。这是否有一些内在的原因,或者 Apple 根本没有着手对这部分 API 进行现代化改造?

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

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

为了能够打电话,

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

我错过了什么吗?这有什么问题吗?

(受 2009 年 Mike Ash 的一篇文章启发,该文章建议不要在块上定义方法。我也在那里发表了评论。)

4

1 回答 1

2

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

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

此外,块从堆栈开始,因此您需要先复制它们,然后再将它们传递给保留它们以供以后执行的方法。为获取块而编写的方法可以解决此问题。大概-[NSUndoManager prepareWithInvocationTarget:]不会复制传入的目标。因此,在传入之前,您需要自己复制块(使用-copyBlock_copy()):

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

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

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

于 2012-07-18T04:40:10.983 回答