在我支持iOS ARC的代码中,我需要将“self”和其他对象传递给一个块。更具体地说,我需要与自己和ASIHTTPRequest
的{{1}}内的ASIHTTPRequest
对象进行互动。
completionBlock
为了避免以下警告:_operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(parseServerReply) object:nil];
_request = [ASIHTTPRequest requestWithURL:@"server.address"];
// ...
[_request setCompletionBlock:^{
[self setResponseString:_request.responseString];
[[MyAppDelegate getQueue] addOperation:_operation];
}];
。我修改了我的代码,以便在此帖子之后添加Capturing "self" strongly in this block will likely lead to a retain cycle
个属性块中使用的对象:Fix warning "Capturing [an object] strongly in this block is likely to lead to a retain cycle" in ARC-enabled code
结果代码是:
__weak
我想知道这是否仍会导致保留周期和内存泄漏。如果是这样,有没有办法避免泄漏?
答案 0 :(得分:14)
你不需要使所有东西变弱,也不想继续引用块中的弱对象(特别是如果块可以在不同的线程中执行)。
这样想。使用ARC时,对象将被引用计数。在引用计数变为零之前,不会在对象上调用dealloc。因此,只要有一个引用,对象就会保持活跃状态。
但是,请考虑两个具有强引用的对象。在另一方发布其引用之前,它们都不会被释放。
创建块时,它会捕获其环境,这意味着它将创建对块范围内使用的任何对象的强引用。
考虑到这一点......
id object = getMeSomeObject();
// <object> is implicitly __strong, and now has a reference.
在释放所有强引用之前,对象不会获得dealloc。如果您在一个块中使用它,该块会自动创建自己的强引用,以确保只要该块存在,该对象就会存在。
__weak引用是一个间接级别,使您可以访问与对象一样长的对象。基本上,如果将对象分配给__weak指针,则只要该对象处于活动状态,该指针就可以保证为您提供相同的对象。一旦对象启动它自己的dealloc(),它会找到所有__weak指针并将它们设置为nil。
因此,您的_weak指针将始终处于两种状态之一。只要对象存在,它就指向一个有效的对象,或者当对象具有dealloc时它指向nil。你应该永远通过弱指针访问一个对象,因为对象可以在你的背后释放,留下一个坏指针。
所以,你想要做的是在堆栈上创建一个__strong引用,这样只要你愿意,对象就会保持活动状态。
在你的情况下......
[_request setCompletionBlock:^{
[self setResponseString:_request.responseString];
[[MyAppDelegate getQueue] addOperation:_operation];
}];
这个区块显然强烈引用了self
。你可能不希望这样。我们试着解决它......
// weakSelf will be "magically" set to nil if <self> deallocs
__weak SelfType *weakSelf = self;
[_request setCompletionBlock:^{
// If <self> is alive right now, I want to keep it alive while I use it
// so I need to create a strong reference
SelfType *strongSelf = weakSelf;
if (strongSelf) {
// Ah... <self> is still alive...
[strongSelf setResponseString:_request.responseString];
[[MyAppDelegate getQueue] addOperation:_operation];
} else {
// Bummer. <self> dealloc before we could run this code.
}
}];
嘿,我们现在有一个弱self
,但是......你仍然会遇到同样的问题。为什么?因为_request和_operation是实例变量。如果访问块内的实例变量,它会隐式创建对self
的强引用。
再给它一次......
// weakSelf will be "magically" set to nil if <self> deallocs
__weak SelfType *weakSelf = self;
[_request setCompletionBlock:^{
// If <self> is alive right now, I want to keep it alive while I use it
// so I need to create a strong reference
SelfType *strongSelf = weakSelf;
if (strongSelf) {
// Ah... <self> is still alive...
[strongSelf setResponseString:strongSelf->_request.responseString];
[[MyAppDelegate getQueue] addOperation:strongSelf->_operation];
} else {
// Bummer. <self> dealloc before we could run this code.
}
}];
现在,您可能不应该在“原始”中使用实例变量,但这是一个不同的主题。
通过这些更改,您有一个不再具有对self的强引用的块,并且如果self
确实是dealloc,则它会正常处理它。
最后,我要重申一下,为了防止在检查weakSelf之后对象消失的潜在问题,必须分配给strongSelf。具体地说...
if (weakSelf) {
// Hey, the object exists at the time of the check, but between that check
// and the very next line, its possible that the object went away.
// So, to prevent that, you should ALWAYS assign to a temporary strong reference.
[weakSelf doSomething];
}
strongSelf = weakSelf;
// OK, now IF this object is not nil, it is guaranteed to stay around as long as
// strongSelf lives.
现在,在这种情况下,块是请求的一部分,它是self
的一部分,因此self
deallocs的可能性很小,但我的主要观点是使用self来防止保留周期,但仍然总是通过强大的参考 - 弱强舞蹈来访问对象。
答案 1 :(得分:1)
您生成的代码是安全的。阅读Brad Larson的答案here了解具体细节。