是否有一种情况可以保留在ARC下的一个街区中的自我?

时间:2012-09-07 18:46:25

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

让我们说我的课看起来像

@interface MyClass {
    MyObject* _object;
    dispatch_queue_t _queue;
}
-(void)myBlocksUsingMethod;
@end

忽略初始化队列的语义,现在我实现

-(void)myBlockUsingMethod {
    dispatch_async(_queue, ^{
        [_object doSomething];
    });
}

如上面的代码所示,在块中保留自己好吗?

我可以重写像

这样的块
-(void)myBlockUsingMethod {
    __weak MyClass* weakSelf = self;
    dispatch_async(_queue, ^{
        MyClass* strongSelf = weakSelf;
        [strongSelf._object doSomething];
    });
}

但是现在是否有必要在这种情况下测试strongSelf == nil,因为我的_queue是我保留的对象的iVar?

此外,如果我的doSomething方法将另一个引用self的块推送到同一队列,会发生什么?这会导致保留周期吗?

2 个答案:

答案 0 :(得分:2)

回答标题中的问题:是的,有很多理由这样做。您可能确定该对象将比该块更长,或者您可能想要创建一个保留周期,该周期将在稍后的特定时间手动中断。

但是,在你的代码中,你做错了。第一种方法(创建对self的隐式强引用的方法)应生成警告。

第二个不应该编译。你有这个:

[strongSelf._object doSomething];

正在调用名为_object的属性,我怀疑是这种情况。所以,也许你的意思是:

[strongSelf.object doSomething];

在这种情况下,您会没事的,因为如果strongSelfnil,则发送给nil的邮件实际上无效。

或者,如果没有财产,也许你真的是这个意思:

[strongSelf->_object doSomething];

在这种情况下,如果strongSelf为nil,程序将会爆炸,因为这不会向nil发送消息,而是取消引用空指针。如果您执行后者,则需要明确检查nil

由于您未访问块中的_queue,因此该访问权限正常。任何直接访问块内的iVar都必须创建一个保留周期以确保对象仍然存活,或者它必须播放弱强舞并检查是否为零。

如果你在多行中使用对象,你还需要做弱强舞,因为弱对象可以在访问之间解除分配(运行时保证如果__weak不是nil,并接受一条消息,那么它将保持活着,直到该消息被处理完毕。)

[weakObject message1];
// weakObject can become nil here
[weakObject message2];

答案 1 :(得分:0)

应该没问题,因为保留周期是暂时的。当调度的操作完成后,它将从队列中删除,因此不再保留该块。