iOS 4阻止并保留计数

时间:2011-04-02 20:09:51

标签: iphone memory-management ios4 retain objective-c-blocks

我刚刚开始使用积木和Grand Central Dispatch。我被告知(并在Apple Documentation中阅读)任何从块中引用的对象都会被保留。

例如:

^{  
    self.layer.transform = CATransform3DScale(CATransform3DMakeTranslation(0, 0, 0), 1, 1, 1);
    self.layer.opacity = 1;
}

“自我”被保留,因此泄漏。为了避免这种情况,我需要将self分配给:

__block Object *blockSelf = self;

然后在我的块中使用blockSelf而不是self

我的问题是:当您的块有更多代码并引用多个对象时会发生什么?我是否需要将它们全部分配给__block个对象?例如:

^{  
    [self doSomething];

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"prevName == %@", artistName];
    [request setEntity:entity];
    [request setPredicate:predicate];

    Object *newObject = [[Object alloc] init];
    [someArray addObject];
    [newObject release];
}

2 个答案:

答案 0 :(得分:48)

没有。当您的块保留一个保留它的对象时,会发生此问题。您的块将保留它引用的任何对象,但使用__block注释的对象除外。因此:

// The following creates a retain cycle which will leak `self`:
self.block = ^{
  [self something];
};

self保留blockblock隐含self。这也将 如果您引用self的实例变量,则会发生。

// The following avoids this retain cycle:
__block typeof(self) bself = self;
self.block = ^{
  [bself something];
};

__block注释的变量是可变的(对于指针,即 他们指出的地址可以改变);结果,没有任何意义 保留该对象,因为您需要将该对象视为局部变量 (如,可以重新分配,影响块范围之外的对象)。因此,__block不会被块保留。

但是,如果您尝试以某种方式使用此块,现在可能遇到无法预料的问题。例如,如果您决定以某种方式延迟调用此块,并且在执行该块时已释放self,则程序将崩溃,因为您正在向已释放的对象发送消息。那么你需要的是一个弱引用,它不是在非垃圾收集环境中开箱即用的!

一种解决方案是使用MAZeroingWeakRef来包裹你的块;如果您在nil被取消分配后尝试发送self消息,那么这会将指针归零,以便您最终向self发送消息:

MAZeroingWeakRef *ref = [MAZeroingWeakRef refWithTarget:self];
self.block = ^{
  [ref.target something];
};

我还实现了weak reference wrapper in Objective-C++,它提供了更轻量级语法的好处:

js::weak_ref<SomeClass> ref = self;
self.block = ^{
  [ref something];
};

因为js::weak_ref是一个类模板,所以你会得到方便的强类型(也就是说,如果你尝试向引用发送一条它没有出现的消息,你会在编译时收到警告回应)。但迈克的MAZeroingWeakReference比我的成熟得多,所以我建议使用他,除非你想弄脏你的手。

要详细了解__block的问题以及弱引用的用例,请阅读Avoiding retain cycles with blocks, a right wayJonathan Rentzsch's response

答案 1 :(得分:2)

我会说这取决于你对你的阻止做什么。如果您没有将它存储在任何地方并在定义位置使用它(比如使用块对数组进行排序),那么它将与其中引用的变量一起释放(因为它是在堆栈中创建的并且标记为自动释放)。如果您将它存储在某个地方(数组,字典或可能将块传递给其他函数)copy块,并在传递之前将其与autorelease进行平衡。