如果我向弱对象发送消息会发生什么?发送消息是否拥有对象并将其保存在内存中直到返回?
我正在考虑这种模式:
__weak MyObject *weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf doSomeAction];
});
假设weakSelf
在发送消息时为非零,它可能在doSomeAction
工作时被释放还是保证在doSomeAction
返回之前保持有效?
如果我向弱对象发送消息会发生什么?发送消息是否拥有对象并将其保存在内存中直到返回?
我正在考虑这种模式:
__weak MyObject *weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf doSomeAction];
});
假设weakSelf
在发送消息时为非零,它可能在doSomeAction
工作时被释放还是保证在doSomeAction
返回之前保持有效?
来自Clang ARC 文档:
对对象左值执行左值到右值转换时会发生读取。
- 对于
__weak
对象,当前指针被保留,然后在当前完整表达式结束时释放。这必须针对分配和指针的最终版本自动执行。
向弱引用发送消息会对变量执行左值到右值的转换,这意味着弱引用的值将被保留,然后在当前完整表达式(基本上是语句)结束时释放。它基本上相当于分配给一个强变量,其范围仅持续当前语句,然后消息传递该强变量。
这里的要点是,如果您想向一个弱变量发送一次消息,并且永远不会再触摸它,并且您不关心在弱引用结束的情况下评估方法参数的副作用nil
,然后去提前并直接向弱引用发送消息。但是,如果您需要两次引用弱引用(在单独的语句中),或者评估参数的副作用确实很重要,那么您应该分配给一个强变量并nil
在继续之前测试 non-。
您问:
假设在发送消息时
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
之间的中间时间被释放,您会看到前者将被调用而后者不会。即,如果没有更多的强引用,则可以在块的中间释放对象。doSomeAction
doSomeAction2
所以,如果你想要弱引用,但想要一种“全有或全无”的行为,在闭包期间保留它,我们执行被戏称为“<code>weakSelf- strongSelf
dance”的操作:
- (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
...
});
}