问题描述
我正在使用ASIHTTPRequest包装器(AsyncImageLoader)数组下载UITableView中单元格的图像.
I'm using an array of ASIHTTPRequest wrappers (AsyncImageLoader) to download images for cells in a UITableView.
我在处理ASIHTTPRequests生存期时遇到问题.如果我释放它们,则当它们尝试加载图像时不断向上和向下滚动时,它们最终将具有EXC_BAD_ACCESS.
I'm having problems handling ASIHTTPRequests lifetime. If I release them, I end up having a EXC_BAD_ACCESS if I keep scrolling up and down while they try to load images.
这是我的包装纸的外观. self.request
具有保留属性,targetCell
是我要在其中放置图像的单元格:
Here's what my wrapper looks like. self.request
has retain property, targetCell
is the cell I want to put the image in:
@implementation AsyncImageLoader
- (void)loadImageFromURL:(NSString*)fileName target:(ResultTableViewCell*)targetCell {
// check for cached images, etc
NSURL* url = [NSURL URLWithString:fileName];
[self.request cancel];
self.request = [ASIHTTPRequest requestWithURL:url];
self.request.delegate = self;
}
- (void)startLoading {
[self.request startAsynchronous];
}
- (void)cancel {
[self.request cancel];
self.request = nil;
}
- (void)requestFinished:(ASIHTTPRequest*)requestDone {
// cache image, set cell image...
self.request = nil;
}
- (void)requestFailed:(ASIHTTPRequest*)requestDone {
// handle answer as well
self.request = nil;
}
@end
loadImageFromURL
在cellForRowAtIndexPath
中为第indexPath.row % 6
个AsyncImageLoader调用,因此,如果我一直上下滚动,则使用同一对象一次又一次地调用它,取消请求,因为它们尚未结束.
loadImageFromURL
is called in cellForRowAtIndexPath
for the indexPath.row % 6
th AsyncImageLoader, so if I keep scrolling up and down it is called again and again with the same object, cancelling requests as they aren't over yet.
但是我总是最终拥有EXC_BAD_ACCESS.根据调用堆栈,它发生在ASIHTTPRequest的markAsFinished
中,该markAsFinished
由failWithError
调用,由[self.request cancel]
在loadImageFromURL:
中调用.在大多数情况下,ASIHTTPRequest已被释放(我在它的dealloc中添加了一个NSLog),但是我不知道这怎么可能,因为ASIHTTPRequest似乎抛出了保留,因此取消时不会被释放.
But I always end up having a EXC_BAD_ACCESS. According to the call stack it happens in ASIHTTPRequest's markAsFinished
, called by failWithError
, called by [self.request cancel]
in loadImageFromURL:
. Most of the time the ASIHTTPRequest was already released (I added a NSLog in it's dealloc), but I don't see how this is possible as the ASIHTTPRequest seems to throw retains so it is not freed while cancelling.
如果我在委托方法中删除了self.request = nil
,我将没有任何EXC_BAD_ACCESS,但是由于ASIHTTPRequests一直在没有取消分配的情况下创建,因此它们最终根本无法正常工作.
I don't have any EXC_BAD_ACCESS if I remove self.request = nil
in the delegate methods, but as ASIHTTPRequests keep being created without deallocation, they end up not working at all.
有人可以告诉我我在做什么错吗?
Could someone tell me what am I doing wrong?
推荐答案
对自己的回答是我的结论和其他答案的综合.
Answering to myself as a synthesis of my conclusion and other answers.
在取消请求时,尤其是在有多个请求且许多请求被迅速取消和释放的情况下,ASIHTTPRequest(或iOS)似乎有点不稳定.
It seems ASIHTTPRequest (or maybe iOS) is a bit unstable when cancelling requests, in particular when there are several requests and many get cancelled and released pretty fast.
作为一种解决方案,我放弃了创建许多请求并在不再需要时取消它们的设计.我做了一个包装,将ASIHTTPRequest
存储在NSOperationQueue
中,该包装还过滤了url,因此同一请求不会两次启动(在出现单元格的情况下,然后在图像完全加载之前消失,然后再次显示).我将所有请求结果(即图像)存储在缓存中.
As a solution I discarded the design of creating many requests and cancelling them if they aren't needed anymore. I made a wrapper storing ASIHTTPRequest
s in a NSOperationQueue
, which also filters urls so the same request is not started twice (in the case a cell appears, then disappears before image is fully loaded, and is displayed again). I store all request results (i.e images) in a cache.
这可能会导致网络活动增加一些,但是随着每个新请求的完成(即使可能不会显示图像)和缓存,其他所有内容都变得更加清晰,因此无需费心创建/取消/其他操作...因此,不再有崩溃.
This results in a possibly slightly higher network activity, but everything else is clearer as every new request is completed (even though the image may not be displayed) and cached, so there's no juggling with creation/cancellation/etc... And consequently no more crash.
这篇关于ASIHTTPRequest解除分配和EXC_BAD_ACCESS问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!