iPhone SDK后台线程图片加载问题

发布于 2024-09-03 13:15:08 字数 1664 浏览 3 评论 0原文

我创建了一个网格视图,显示六个“单元格”的内容。在每个单元格中,都会从网络加载图像。该网格有多个页面(用户通过向上/向下滑动来浏览它们以查看下一组单元格)。

每个单元都有自己的视图控制器。当这些视图控制器加载时,它们使用我制作的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

渔村楼浪 2024-09-10 13:15:08

有一半时间我在这里问问题,很快我就会想出一个解决方案。写下问题可能就解决了 90% 的问题。

无论如何,这就是我所做的,并且可能需要对此进行改进,因为我仍然对线程持怀疑态度。

事实证明,问题在于委托方法仍然会触发(imageDidFinishLoading),但委托已被释放。通过在释放委托时在 GridCellViewController.m 中将委托显式设置为 nil,该消息永远不会触发。

GridCellViewController.m

- (void) dealloc {
    if(_loader) {
        _loader.delegate = nil;
        [_loader release];
    }
}

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

- (void) dealloc {
    if(_loader) {
        _loader.delegate = nil;
        [_loader release];
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文