14

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

我正在考虑这种模式:

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

假设weakSelf在发送消息时为非零,它可能在doSomeAction工作时被释放还是保证在doSomeAction返回之前保持有效?

4

2 回答 2

20

来自Clang ARC 文档

对对象左值执行左值到右值转换时会发生读取。

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

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

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

于 2013-02-22T21:47:59.250 回答
5

您问:

假设在发送消息时weakSelf是 non- nil,它可能在doSomeAction工作时被释放还是保证在doSomeAction返回之前保持有效?

这种 ARC 行为随着时间的推移而发生了变化。但是现在,weak只要删除最后一个强引用,就可以释放引用。

因此,请考虑以下事项:

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

- (void)startBackgroundOperation {
    __weak typeof(self) weakSelf = self;
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [weakSelf doSomeAction];
        [NSThread sleepForTimeInterval:5];
        [weakSelf doSomeAction2];
    });
}

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

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

如果您有一些代码调用并让对象在andstartBackgroundOperation之间的中间时间被释放,您会看到前者将被调用而后者不会。即,如果没有更多的强引用,则可以在块的中间释放对象。doSomeActiondoSomeAction2

所以,如果你想要弱引用,但想要一种“全有或全无”的行为,在闭包期间保留它,我们执行被戏称为“<code>weakSelf- strongSelfdance”的操作:

- (void)startBackgroundOperation {
    __weak typeof(self) weakSelf = self;

     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        typeof(self) strongSelf = weakSelf;        // establish just-in-time strong reference (if `weakSelf` is not yet `nil`)

        [strongSelf doSomeAction];
        [NSThread sleepForTimeInterval:5];
        [strongSelf doSomeAction2];
    });
}

这将确保该块有一个weak引用,但如果它在分配 时没有被释放strongSelf,那么它将在该块的持续时间内建立并维护一个强引用。


对于它的价值,这种weakSelf-strongSelf模式在取消引用 ivars 时必不可少->(避免使用 的竞争条件weakSelf)。

例如

- (void)badDeferenceExample {
    __weak typeof(self) weakSelf = self;

     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        if (!weakSelf) { return; }

        NSInteger value = weakSelf->_someIVar;     // this is race and can crash!!!

        ...
    });
}

- (void)properDeferenceExample {
    __weak typeof(self) weakSelf = self;

     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        typeof(self) strongSelf = weakSelf;        // establish just-in-time strong reference (if `weakSelf` is not yet `nil`)

        if (!strongSelf) { return; }

        NSInteger value = strongSelf->_someIVar;   // this is safe

        ...
    });
}
于 2013-02-23T03:53:59.743 回答