【问题标题】:Objective-C: blocks in ARCObjective-C:ARC中的块
【发布时间】:2013-02-01 09:45:26
【问题描述】:

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

块在 ARC 中是如何工作的?

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

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

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

【问题讨论】:

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


    【解决方案1】:

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

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

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

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

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

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

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

    【讨论】:

    • 这似乎解决了所有问题。最后一段也是一个很好的提示。感谢您的澄清!
    猜你喜欢
    • 2013-01-05
    • 1970-01-01
    • 1970-01-01
    • 2011-04-25
    • 2011-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-27
    相关资源
    最近更新 更多