【发布时间】:2012-07-10 11:42:56
【问题描述】:
我试图了解在操作的完成块中引用对象时,让对象在其 dealloc 方法中取消网络操作是否是个好主意。
我会尝试用一个例子来解释:
我有一个User 对象,其属性为picture,User 有一个[self fetchPictureFromServer]:
- (void)fetchPictureFromServer
{
NSDictionary *cmdParameters = ...; // set parameters
__block User *weakSelf = self;
[[AppClient sharedClient] sendCommand:@"getpicture" parameters:cmdParameters success:^(AFHTTPRequestOperation *operation, id response)
{
// success
UIImage *downloadedImage = ...; // get image from response
weakSelf.picture = downloadedImage; // set image to user's picture property
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// failed
}];
sendCommand 方法将创建(并排入NSOperationQueue 队列)NSOperation,该NSOperation 将及时启动NSURLConnection 以下载图像。当操作成功完成时,成功块将被调用。
我使用weakSelf 是因为我不希望该块保留我的用户对象(并防止它被释放),我希望用户负责取消现有操作(如果存在)他得到了释放。
所以 User dealloc 方法看起来像这样:
- (void)dealloc
{
[[AppClient sharedClient] cancelAllCommandsForSender:self];
[super dealloc];
}
但似乎虽然我在dealloc方法中取消了操作,但有时在用户获得dealloc之后调用成功块,并且我在weakSelf.picture = downloadedImage行中得到EXC_BAD_ACCESS。
为什么会这样?会不会是操作被取消了也试图完成连接?
我知道如果我在块中只使用 self 而不是weakSelf,这不会发生,因为块会保留用户。但我不希望这种行为,我希望用户在释放时立即获得 dealloc,即使存在获取操作。
更新: 我注意到操作状态是Finished = YES,似乎使用我使用的库,当操作完成时,它不会立即执行成功块,而是将成功块与主队列dispatch_async。
所以正确的情况是:
1. 用户获取图片 -> 一个操作被创建
2.操作完成 -> dispatch_async 成功块(仍然没有执行)
3.在执行成功块之前,用户dealloc -> 取消他的所有操作(但不是step1的操作,因为它处于isFinished状态)
4. 现在执行成功块 -> 我在尝试引用用户时得到 EXC_BAD_ACCESS。
仍然不知道如何解决这个问题..
【问题讨论】:
-
请看我的更新
-
是ARC项目吗(问是因为
__block的语义在ARC下不一样),你的部署目标是5.0+吗? -
weakSelf 需要在块的第一行使用,否则无效。解决方法是让它变得 strongSelf,例如“__strong typeof(self) strongSelf = weakSelf;”在第一行,然后你可以使用 strongSelf 之后。
标签: objective-c ios objective-c-blocks nsoperation