如何使用ARC释放块

时间:2013-11-26 08:47:07

标签: ios objective-c objective-c-blocks

描述

我将块传递给异步方法,并在操作完成时调用它。我想在操作完成之前拒绝调用块。但是如果我将nil分配给我的类中的块变量,那么无论如何都要调用它。我调试了它,我看到如果我将nil分配给块变量1,则变量2不是nil。下面的代码说明了这一点:

void (^d1)(NSArray *data) = ^(NSArray *data) {};

void (__weak^d2)(NSArray *data) = d1;

d1 = nil;

输出

(lldb) po d1
<__NSGlobalBlock__: 0x9c22b8>]
(lldb) po d2
<__NSGlobalBlock__: 0x9c22b8>
(lldb) po d1
<nil>
(lldb) po d2
<__NSGlobalBlock__: 0x9c22b8>

问题

为什么阻止d2不是零?是按值复制而不是复制为指针?

2 个答案:

答案 0 :(得分:5)

首先,您永远不应该依赖于在特定位置释放的对象。在您不知情的情况下,其他人(例如自动释放池)始终可以保留对它的引用。对象不能在任何地方解除分配是不正确的。

好的,就你的情况而言:__NSGlobalBlock__给出了一个提示:这是一个“全局块”。在块的当前实现中,有3种类型的块对象:堆栈块(__NSStackBlock__),堆块(__NSMallocBlock__)和全局块(__NSGlobalBlock__)。

闭包的块(即使用来自外部作用域的一些局部变量)从“堆栈块”开始 - 对象结构具有自动存储持续时间,就像局部变量一样,并且当它离开它定义的作用域时它变为无效。当堆栈块被“复制”时,它会被移动到堆上动态分配的对象,就像Objective-C中的所有其他对象一样。这是一个堆块。它与Cocoa中的其他对象一样被引用计数,复制它与retain相同。

不是闭包的块(这是你的例子中的块)被实现为“全局块”。因为它不包含任何捕获的变量,所以块的所有实例都是相同的,因此在整个程序中只有一个实例。它像字符串文字一样静态分配,并且在程序的整个生命周期中都存在。它不是引用计数,保留,释放和复制它不起作用。它不能被解除分配;这就是为什么你的弱引用永远不会被设置为nil__weak引用只有在它指向的对象被取消分配时才会设置为nil

答案 1 :(得分:1)

d1是对您创建的块^(NSArray *data) {};的引用。将d2分配给d1的引用后,该块上的引用计数会递增。当你将d1设置为nil时,仍然有一个指向块的强指针,d2。