Objective-C: ARC中的块

7
我正在转换到ARC(自动引用计数),这篇文档非常有帮助:Transitioning to ARC Release Notes。它说:
块在ARC中如何工作?
在ARC模式下,当您将块通过堆栈传递时(例如在返回值中),块“只需工作”。您不再需要调用Block Copy。但是,当向arrayWithObjects:和执行保留的其他方法传递“向下”堆栈时,仍然需要使用[^{}] copy。
有人可以详细解释一下或举个例子吗? 我理解这意味着即使块在声明范围之外使用,现在ARC会更加智能地处理它,通常我不再需要做[block copy],但是当我想将块传递给将保留它的函数时,我仍然需要复制它。 这正确吗?
实际上,我已经进行了一些实验,即使我没有复制块就将其传递给数组,目前看起来也没问题,所以问问这个问题。 谢谢!
1个回答

15
让我们从MRC(手动引用计数)的角度考虑这个问题。当你从一个函数返回一个堆栈块时,始终将其复制(通常使用 [[copy] autorelease])是正确的做法。这是因为堆栈块的生命周期是该函数调用,即将结束。因此,为了在返回后使指针指向有效块,当然必须返回堆副本。
然而,如果将块作为参数传递给函数或方法,情况会如何呢?这有点复杂。我们知道,如果需要在稍后使用的位置存储块(例如实例变量或全局变量等),则需要存储块的副本。但是,我们如何知道这是真的(如果是真的,哪个函数(调用方/被调用方)负责复制它)?
一般来说,当将块传递给参数为块类型的函数或方法时,您不需要复制它,因为作为接受块参数的函数,如果需要将其存储以供稍后使用,则该函数负责复制它。
但是,如果将块传递给参数为非块类型(如id)的函数或方法呢?那么该函数不知道其参数是块,因此仅在需要稍后存储对象时才会保留对象,而不会复制它。在这种情况下,如果我们知道函数或方法将以后存储该对象(例如使用-[NSMutableArray addObject:]),则应传递块的副本。我们应该总是传递一个副本吗?不一定。如果我们知道该函数或方法不会稍后存储块(例如仅打印对象),则复制块是低效的。
在ARC中,编译器尽可能为您完成工作。因此,在返回堆栈块时(“向上传递”),编译器知道返回副本始终是正确的做法,因此隐式执行此操作。这就是为什么您不再需要自己完成此操作的原因。然而,对于将代码块传递给方法或函数(“向下传递”)来说,并不总是可以自动确定是否需要复制,而且额外的复制可能效率低下,因此编译器不会自动执行任何操作;程序员需要自己找出解决方法。
我注意到在最近版本的编译器中,ARC 在许多情况下都会复制代码块,这比我想象的要多得多,因此可能他们改变了 ARC 的实现方式,以便于谨慎起见几乎总是复制代码块,并且他们认为性能成本并不重要。因此,现在有可能直接将代码块传递给 addObject: 而无需明确复制。但我相信,在 ARC 之前并非始终如此,并且语言中也没有保证这一行为会保持不变。

看起来这样就解决了。最后一段也是一个好提示。感谢澄清! - K J

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接