Objective-C:ARC中的块

时间:2013-02-01 09:45:26

标签: objective-c automatic-ref-counting objective-c-blocks

我正在转换到ARC(自动引用计数),这个文档非常有用:Transitioning to ARC Release Notes。它说:

  

块如何在ARC中工作?

     

在ARC模式下将块传递到堆栈时阻止“正常工作”,例如在返回中。您不必再调用Block Copy。将堆栈“向下”传递给arrayWithObjects:以及其他执行保留的方法时,仍然需要使用[^ {} copy]。

有人可以详细说明这一点或举一些例子吗?我明白这通常意味着我不需要再进行[块复制],即使块在声明范围之外使用,因为ARC现在会更加巧妙地处理它,但我仍然需要在我想要时复制它将块传递给保留它的函数。这是对的吗?

实际上我已经尝试了一点点,到目前为止,即使我将数据块传递给数组而没有复制也似乎没问题,所以这个问题。谢谢!

1 个答案:

答案 0 :(得分:13)

让我们从MRC(手动引用计数)的角度考虑问题。当您从函数返回堆栈块时,总是正确的返回它的副本(通常使用[[ copy] autorelease])。这是因为堆栈块的生命周期是函数调用,它正在结束。因此,为了使返回的指针在返回后指向有效的块,当然您必须返回堆副本。

但是,将块作为参数传递给函数或方法呢?你应该通过它的副本吗?这有点复杂。我们知道,如果你需要存储一个块供以后在一个比函数调用更长的地方使用(例如在一个实例变量或全局变量等中),你需要存储一个块的副本。但是我们怎么知道这是真的(如果它是真的,哪个函数(调用者/被调用者)负责复制它?)

通常,当您将其传递给参数为块类型的函数或方法时,您不需要复制它,因为,作为一个带有块参数的函数,该函数负责复制它,如果它需要将它存储起来以备日后使用。

但是将块传递给参数为非块类型的函数或方法(如id)呢?然后该函数不知道它的参数是一个块,因此只有在需要存储它以供以后使用时才会保留该对象,而不是复制它。在这种情况下,如果我们知道函数或方法将存储对象以供以后使用(例如使用-[NSMutableArray addObject:]),我们应该传递该块的副本。我们应该总是传递副本吗?不必要。如果我们知道函数或方法不会存储块以供以后使用(例如只打印对象),那么制作块的副本效率很低。

在ARC中,编译器会尝试尽可能多地为您执行操作。因此,在返回堆栈块(“传递它”)的情况下,编译器知道返回副本总是正确的,所以它隐含地这样做。这就是为什么你不再需要自己动手了。

但是,为了将块传递给方法或函数(“传递它”),并不总是能够自动确定是否需要复制,并且额外复制可能效率低,因此编译器不会自动做任何事情;程序员需要弄明白。

我注意到在最近版本的编译器中,ARC会在很多情况下复制块,我想也许,所以也许他们将ARC的实现改为几乎总是复制块,以便在错误的一面谨慎,他们认为性能成本并不重要。所以它现在可以直接将块传递给addObject:而无需显式复制。但我相信ARC并不总是如此,并且语言无法保证这一点,或者这种行为将来会保留。