2

我从事同一个项目已经有一段时间了,随着时间的推移,我对 Objective-C 和 Cocoa 的理解也有了一些变化。回顾我的代码的某些部分,我看到了这一点:

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

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

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

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

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

更新:根据这个问题,正确的做法是这样的:

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

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

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

4

3 回答 3

3

引用Apple 的 Programming with ARC发行说明:

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

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

虽然在初始赋值后使用了字符串,但在赋值时并没有其他对字符串对象的强引用;因此,它立即被解除分配。日志语句显示该字符串具有空值。

于 2012-09-05T21:20:00.907 回答
0

我相信这是因为您在一个块中运行弱变量。该块保持弱变量的状态,从而使其工作。一旦块完成,我打赌在变量上做很多工作可能会导致问题。

如果您多次运行它,我猜测它为什么会失败是因为异步 asi 调用堆栈变得很高并且会爆炸。我以前见过这个,如果你非常有耐心,你可以在调试器中捕捉到 asi 爆炸。

于 2012-09-05T21:52:30.370 回答
0

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

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

块扩展了方法范围,因为它们暗示了潜在的异步行为,并且它们利用了调用它们时存在的堆栈。

于 2012-09-06T08:08:11.167 回答