iPhone SDK后台线程图片加载问题
我创建了一个网格视图,显示六个“单元格”的内容。在每个单元格中,都会从网络加载图像。该网格有多个页面(用户通过向上/向下滑动来浏览它们以查看下一组单元格)。
每个单元都有自己的视图控制器。当这些视图控制器加载时,它们使用我制作的 ImageLoader 类来加载和显示图像。这些视图控制器实现一个 ImageLoaderDelegate,它有一个方法,当图像加载完成时会调用该方法。
ImageLoader 在后台线程上完成工作,然后在加载完成时通知其委托,将图像传递给委托方法。
问题是,如果用户在图像加载完成之前移动到网格内容的下一页(释放使用 ImageLoaders 的 GridCellViewControllers),应用程序就会崩溃。我怀疑这是因为异步方法完成并尝试通知其委托但不能,因为它已被释放。
下面是一些代码,可以提供更好的图片:
GridCellViewController.m:
- (void)viewDidLoad {
[super viewDidLoad];
// ImageLoader
_loader = [[ProductImageLoader alloc] init];
_loader.delegate = self;
if(_boundObject)
[_loader loadImageForProduct:_boundObject];
}
//ImageLoaderDelegate method
- (void) imageDidFinishLoading: (UIImage *)image {
[_imgController setImage:image];
}
ProductImageLoader.m
- (void) loadImageForProduct: (Product *) product {
// Get image on another thread
[NSThread detachNewThreadSelector:@selector(getImageForProductInBackground:) toTarget:self withObject:product];
}
- (void) getImageForProductInBackground: (Product *) product {
NSAutoreleasePool *tempPool = [[NSAutoreleasePool alloc] init];
HttpRequestLoader *tempLoader = [[HttpRequestLoader alloc] init];
NSURL *tempUrl = [product getImageUrl];
NSData *imageData = tempUrl ? [tempLoader loadSynchronousDataFromAddress:[tempUrl absoluteString]] : nil;
UIImage *image = [[UIImage alloc] initWithData:imageData];
[tempPool release];
if(delegate)
[delegate imageDidFinishLoading:image];
}
应用程序因 EXC_BAD_ACCESS 崩溃。
免责声明:代码已稍作修改,以专注于当前的问题。
I have created a grid view that displays six "cells" of content. In each cell, an image is loaded from the web. There are a multiple pages of this grid (the user moves through them by swiping up / down to see the next set of cells).
Each cell has its own view controller. When these view controllers load, they use an ImageLoader class that I made to load and display an image. These view controllers implement an ImageLoaderDelegate that has a single method that gets called when the image is finished loading.
ImageLoader does its work on a background thread and then simply notifies its delegate when it is done loading, passing the image to the delegate method.
Trouble is that if the user moves on to the next page of grid content before the image has finished loading (releasing the GridCellViewControllers that use the ImageLoaders), the app crashes. I suspect that this is because along the line, an asynchronous method finishes and attempts to notify its delegate but can't because it's been released.
Here's some code to give a better picture:
GridCellViewController.m:
- (void)viewDidLoad {
[super viewDidLoad];
// ImageLoader
_loader = [[ProductImageLoader alloc] init];
_loader.delegate = self;
if(_boundObject)
[_loader loadImageForProduct:_boundObject];
}
//ImageLoaderDelegate method
- (void) imageDidFinishLoading: (UIImage *)image {
[_imgController setImage:image];
}
ProductImageLoader.m
- (void) loadImageForProduct: (Product *) product {
// Get image on another thread
[NSThread detachNewThreadSelector:@selector(getImageForProductInBackground:) toTarget:self withObject:product];
}
- (void) getImageForProductInBackground: (Product *) product {
NSAutoreleasePool *tempPool = [[NSAutoreleasePool alloc] init];
HttpRequestLoader *tempLoader = [[HttpRequestLoader alloc] init];
NSURL *tempUrl = [product getImageUrl];
NSData *imageData = tempUrl ? [tempLoader loadSynchronousDataFromAddress:[tempUrl absoluteString]] : nil;
UIImage *image = [[UIImage alloc] initWithData:imageData];
[tempPool release];
if(delegate)
[delegate imageDidFinishLoading:image];
}
The app crashes with EXC_BAD_ACCESS.
Disclaimer: The code has been slightly modified to focus on the issue at hand.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
有一半时间我在这里问问题,很快我就会想出一个解决方案。写下问题可能就解决了 90% 的问题。
无论如何,这就是我所做的,并且可能需要对此进行改进,因为我仍然对线程持怀疑态度。
事实证明,问题在于委托方法仍然会触发(imageDidFinishLoading),但委托已被释放。通过在释放委托时在 GridCellViewController.m 中将委托显式设置为 nil,该消息永远不会触发。
GridCellViewController.m
Half the time I ask a question on here, I come up with a solution shortly after. Writing down the issue is probably 90% of the solution.
Anyway, here's what I did, and there is probably an improvement to be made to this as I'm still suspicious of the threads.
As it turns out the problem was that the delegate method would still fire (imageDidFinishLoading), but the delegate had been released. By explicitly setting the delegate to nil in GridCellViewController.m when it is released, the message never fires.
GridCellViewController.m