传递一个__weak对象?

Ste*_*her 13 ios automatic-ref-counting

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

我在考虑这种模式:

__weak MyObject *weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
    [weakSelf doSomeAction];
});
Run Code Online (Sandbox Code Playgroud)

假设weakSelf在发送消息时为非零,是否可以在doSomeAction工作时解除分配,或者保证在doSomeAction返回之前保持有效?

Lil*_*ard 19

Clang ARC文档:

读数执行上的对象的左值一个左值到右值转换时,会发生.

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

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

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


Rob*_*Rob 5

你问:

假设weakSelf是不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__);
}
Run Code Online (Sandbox Code Playgroud)

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

所以,如果你想要弱引用,但想要一个“全有或全无”的行为,从而在闭包期间保留它,我们执行被戏称为“ weakSelf-strongSelf舞蹈”的动作:

- (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];
    });
}
Run Code Online (Sandbox Code Playgroud)

这将确保该块有一个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

        ...
    });
}
Run Code Online (Sandbox Code Playgroud)