【问题标题】:Is there ever a situation where retaining self in a block under ARC is ok?有没有一种情况可以在 ARC 下将 self 保留在一个块中?
【发布时间】:2012-09-07 18:46:24
【问题描述】:

假设我的班级看起来像

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

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

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

如上代码所示,在块中保留 self 可以吗?

我可以像这样重写块

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

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

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

【问题讨论】:

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


    【解决方案1】:

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

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

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

    [strongSelf._object doSomething];
    

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

    [strongSelf.object doSomething];
    

    在这种情况下,你会没事的,因为如果 strongSelfnil,那么发送到 nil 的消息实际上什么都不做。

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

    [strongSelf->_object doSomething];
    

    在这种情况下,如果 strongSelf 为 nil,您的程序将崩溃,因为这不是向 nil 发送消息,而是取消引用空指针。如果你做后者,你需要明确检查nil

    由于您没有访问块中的_queue,因此该访问权限很好。对块内 iVar 的任何直接访问都必须创建一个保留循环以确保对象仍然存在,或者它必须执行弱-强-dance 并检查 nil。

    如果你在多行中使用对象,你还需要做弱强舞,因为弱对象可以在访问之间释放(运行时保证如果 __weak 不是 nil 并接受消息,那在处理该消息之前,它将保持活动状态)。

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

    【讨论】:

    • 我的意思是输入-> 而不是.,正如您正确指出的那样。感谢您的写作。
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2019-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多