6

我正在过渡到 ARC(自动引用计数),这份文档非常有帮助:Transitioning to ARC Release Notes。它说:

块如何在 ARC 中工作?

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

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

实际上,我已经对其进行了一些试验,到目前为止,即使我将块传递给数组而不进行复制,它似乎也可以,所以这个问题。谢谢!

4

1 回答 1

14

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

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

一般来说,当你将它传递给参数为块类型的函数或方法时,你不需要复制它,因为作为一个接受块参数的函数,如果需要,该函数负责复制它把它储存起来以备后用。

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

在 ARC 中,编译器会尽力为您做尽可能多的事情。所以在返回一个堆栈块(“向上传递”)的情况下,编译器知道返回一个副本总是正确的,所以它隐式地这样做了。这就是为什么你不再需要自己做。

但是,对于将块传递给方法或函数(“向下传递”),并不总是可以自动确定是否需要复制,并且额外的复制可能效率低下,因此编译器不会自动执行任何操作; 你程序员需要弄清楚。

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

于 2013-02-02T03:13:30.120 回答