传递一个__weak对象?

时间:2013-02-22 21:42:37

标签: ios automatic-ref-counting

如果我向弱对象发送消息会怎样?发送消息是否拥有该对象并将其保存在内存中直到返回?

我正在考虑这种模式:

__weak MyObject *weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
    [weakSelf doSomeAction];
});

假设发送邮件时weakSelf为非零,可能会在doSomeAction正常工作时取消分配,还是保证在doSomeAction返回之前保持有效?

2 个答案:

答案 0 :(得分:19)

来自Clang ARC documentation

  在对象左值上执行左值到右值转换时,会发生

读取

     
      
  • 对于__weak个对象,保留当前的指针对象,然后在当前的完整表达式结束时释放。这必须在分配和指针的最终版本方面以原子方式执行。
  •   

对弱引用进行消息传递对变量执行左值到右值的转换,这意味着弱引用的值将被保留,然后在当前的完整表达式(基本上是语句)结束时释放。它基本上等同于分配一个强变量,其范围仅适用于当前语句,然后传递该强变量。

这里要说的是,如果你想要一次发送一个弱变量,再也不要再触摸它,你就不关心在弱参考结束的情况下评估方法参数的副作用nil,然后继续直接向弱引用发送消息。但是如果你需要两次引用弱引用(在单独的语句中),或者评估参数的副作用很重要,那么你应该在继续之前分配一个强变量并测试非nil

答案 1 :(得分:4)

你问:

  

假设weakSelf在发送邮件时不是nil,可能会在doSomeAction正在运行时取消分配,还是保证在doSomeAction返回之前保持有效?

是的,不仅在doSomeAction返回之前它仍然有效,它也会保留在块的其余部分。请考虑以下事项:

- (void)dealloc
{
    NSLog(@"%s", __FUNCTION__);
}

- (void)startBackgroundOperation
{
    __weak MyObject * weakSelf = self;

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [weakSelf doSomeAction];
        sleep(5);
        [weakSelf doSomeAction2];
    });

    sleep(1);
}

- (void)doSomeAction
{
    NSLog(@"%s", __FUNCTION__);
}

- (void)doSomeAction2
{
    NSLog(@"%s", __FUNCTION__);
}

在这个例子中,我确保当块开始时对象在范围内,但是让它超出doSomeActiondoSomeAction2之间的范围,但是块似乎保留了它完成块。但是,如果我注释掉doSomeAction的调用,weak引用在到达nil时就会doSomeAction2,就像您期望的那样。


另外,在WWDC 2011 - #322 - Objective-C Advancements In-Depth中,他们指出(大约27:00分钟进入视频),他们指出如果您要取消引用weakSelf,则应该有一个本地强引用在调度区内,以保护自己在竞争条件下,因此:

__weak MyClass *weakSelf = self;

dispatch_async(dispatch_get_main_queue(), ^{
    MyClass *strongSelf = weakSelf;
    if (strongSelf)
        [strongSelf->myView doSomeViewAction];
});

这将在块的持续时间内保留它(假设它在块执行时尚未释放)。