为什么使用__weak不会导致局部变量立即出错?

时间:2012-09-05 20:54:56

标签: iphone objective-c ios automatic-ref-counting

我已经在同一个项目上工作了一段时间,而且我对Objective-C和Cocoa的理解已经发展了一段时间。回顾一下代码的某些部分,我看到了:

__weak ASIFormDataRequest *serverQueueRequest = [ASIFormDataRequest requestWithURL:url2];
[serverQueueRequest setCompletionBlock:^{
    NSLog(@"%@", serverQueueRequest.responseString);
}];
[serverQueueRequest startAsynchronous]; 

这就是我处理所有服务器请求的方式。我想我这样做是为了抑制警告,即“在块中捕获请求可能会导致保留周期”。所以我把它变弱了,这似乎解决了我所有的问题。我没有发现任何真正的问题。

但是,现在查看代码,它的工作原理似乎有些奇怪。当我将请求声明为__weak时,它不应该立即归零,因为没有人坚持它吗?为什么这段代码有效?

此外,虽然这段代码有效,但我最近发现了一个不这样的情况:当连续多次调用包含此代码的方法时,在一秒钟内调用5次,3/5请求将得到NULL回复。情况一直如此。删除__weak限定符可解决此问题。对此有何解释?

最后,声明像这样的本地请求的正确方法是什么?

更新:根据this question,正确的方法就是这样:

ASIHTTPRequest *_request = [[ASIHTTPRequest alloc] initWithURL:...
__weak ASIHTTPRequest *request = _request;

编辑:实际上上面的修复不能解决调用代码5次导致NULL响应的问题。那个问题依然存在。问题消失的唯一方法是强烈捕获请求而不使用任何限定符。

现在的问题是为什么我的原始代码仍然有效..

3 个答案:

答案 0 :(得分:3)

引自Apple's Programming with ARC发行说明:

  

在堆栈上使用__weak变量时要小心。考虑一下   以下示例:

NSString __weak *string = [[NSString alloc] initWithFormat:@"First Name: %@", [self firstName]]; 
NSLog(@"string:%@", string); 
  

虽然在初始分配后使用了字符串,   当时没有对字符串对象的其他强引用   分配;因此,它立即被解除分配。日志声明   表明字符串具有空值。

答案 1 :(得分:0)

我相信这是因为你在一个块中运行弱变量。该块保持弱变量的状态,从而使其起作用。一旦块完成,我就会对变量进行大量工作可能会导致问题。

我猜测如果你多次运行它失败的原因是因为异步asi调用堆栈变得很高并且炸弹。我以前见过这个,如果你很耐心,你可以在调试器中看到asi爆炸。

答案 2 :(得分:0)

obj C堆栈将始终保留范围内的指针。 _weak并不意味着现在释放它意味着当堆栈超出范围时释放。

当你声明一个var然后在同一个堆栈范围内对它进行调用时,它将不会被释放,直到(最低限度)清理堆栈。

阻止扩展方法范围,因为它们意味着潜在的异步行为,并且它们利用调用它们时存在的堆栈。