可以使用__weak属性传递参数块导致内存泄漏?

在我支持iOS的ARC代码中,我需要将“self”和其他对象传递给一个块。 更具体地说,我需要在ASIHTTPRequestcompletionBlock内部与self和一个ASIHTTPRequest对象进行交互。

 _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 。 我已经修改了我的代码,以添加__weak属性在这个post后面的块中使用的对象: 修复警告“在该块强烈捕获[一个对象]很可能导致一个保留周期”在启用ARC的代码

结果代码是:

 _operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(parseServerReply) object:nil]; _request = [ASIHTTPRequest requestWithURL:@"server.address"]; // ... __weak NSOperation * operation = _operation; __weak ASIHTTPRequest * request = _request; __weak typeof(self) * self_ = self; [request setCompletionBlock:^{ [self_ setResponseString:request.responseString]; [[MyAppDelegate getQueue] addOperation:operation]; }]; 

我想知道这是否仍然可以导致保持循环和内存泄漏。 如果是这样,是否有办法避免泄漏?

你不需要让所有的东西都变得脆弱,也不需要在块中引用一个弱对象(尤其是如果这个块可以在不同的线程中执行的话)。

想想这样。 使用ARC时,对象被引用计数。 在引用计数变为零之前,不会在对象上调用dealloc。 所以,只要有一个引用,对象将保持活着。

但是,考虑两个彼此有很强关联的对象。 直到另一个释放它的引用才会释放。

当你创build一个块时,它会捕获它的环境,这意味着它将创build对该块范围内使用的任何对象的强引用。

考虑到这一点…

 id object = getMeSomeObject(); // <object> is implicitly __strong, and now has a reference. 

在所有强引用被释放之前,对象不会被释放。 如果你在一个块中使用它,块会自动创build自己的强引用,以确保对象的存活时间与块的存在时间一样长。

__weak引用是一个间接的级别,使您可以访问与对象一样长的对象。 基本上,如果将一个对象分配给__weak指针,那么只要该对象处于活动状态,该指针就能保证给予同一个对象。 一旦对象启动它自己的dealloc(),它就会find所有__weak指针,并将它们设置为nil。

所以,你的_weak指针总是处于两种状态之一。 只要对象存在,它就指向一个有效的对象,或者当对象具有dealloc时它是零。 你不应该通过一个弱指针来访问一个对象,因为这个对象可能会在你后面释放,给你一个不好的指针。

所以,你想要做的就是在堆栈上创build一个__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是实例variables。 如果你访问一个块内的一个实例variables,它会隐式地创build一个强的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. } }]; 

现在,你可能不应该使用实例variables“原始”,但这是一个不同的话题。

随着这些变化,你有一个块不再有一个强烈的自我,如果self真的dealloc,它处理它优雅。

最后,我将重申,强自己的任务是必要的,以防止对象消失后,检查weakSelf的潜在问题。 特别…

 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释放的可能性很小,但我的主要观点是使用self来防止保留周期,但仍然总是通过强烈的参考 – 弱的舞蹈。

您的结果代码是安全的。 请阅读Brad Larson的答案。