如果我向弱对象发送消息会怎样?发送消息是否拥有该对象并将其保存在内存中直到返回?
我正在考虑这种模式:
__weak MyObject *weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf doSomeAction];
});
假设发送邮件时weakSelf
为非零,可能会在doSomeAction
正常工作时取消分配,还是保证在doSomeAction
返回之前保持有效?
答案 0 :(得分:19)
在对象左值上执行左值到右值转换时,会发生读取 。
- 对于
__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__);
}
在这个例子中,我确保当块开始时对象在范围内,但是让它超出doSomeAction
和doSomeAction2
之间的范围,但是块似乎保留了它完成块。但是,如果我注释掉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];
});
这将在块的持续时间内保留它(假设它在块执行时尚未释放)。