UITableViewCell加载图像和重用的单元格

时间:2012-02-08 02:47:24

标签: ios uitableview

我需要从web /文件中加载一些UIImages。我正在搜索,我在其他question这段代码中找到了:

    if (![[NSFileManager defaultManager] fileExistsAtPath:user.image]) {
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,  0ul);
        dispatch_async(queue, ^{
            NSData *imageData =[NSData dataWithContentsOfURL:[NSURL URLWithString:user.imageURL]];

            [imageData writeToFile:user.image atomically:YES];
            dispatch_sync(dispatch_get_main_queue(), ^{
                UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
                UIImage *image = [UIImage imageWithData:imageData];
                [self.imageFriends setObject:image forKey:[NSNumber numberWithInt:user.userId]];
                cell.imageView.image = image;
                [cell setNeedsLayout];
                NSLog(@"Download %@",user.image);
            });
        });
        cell.imageView.image=[UIImage imageNamed:@"xger86x.jpg"];
    } else {
        NSLog(@"cache");
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,  0ul);
        dispatch_async(queue, ^{
            UIImage *image = [UIImage imageWithContentsOfFile:user.image];
            //[self.imageFriends setObject:image forKey:[NSNumber numberWithInt:user.userId]];
            dispatch_sync(dispatch_get_main_queue(), ^{
                UITableViewCell *newCell = [tableView cellForRowAtIndexPath:indexPath];
                newCell.imageView.image=image;
                [newCell setNeedsLayout];
            });
        });
    }

但问题是,当我快速滚动到底部或顶部时,图像加载错误,并且在结束时存在短暂的延迟。

所以问题是..当我使用队列来获取它们时,如何在正确的单元格中加载UIImages?谢谢!

2 个答案:

答案 0 :(得分:7)

我怀疑您看到的图像不正确是因为如果您拥有图像的本地副本但仍然异步检索本地副本,则不会设置占位符图像。此外,在您为加载本地副本而附加的代码中,您在后台线程上使用UIImage UIKit组件。

另外有趣的是,您似乎正在进行某种UIImage缓存。将图像添加到我假设的是名为NSMutableArray的{​​{1}}属性。但是,如果您拥有该文件的本地副本,您似乎已经注释掉了缓存添加。此外,您发布的代码也不会使用缓存的imageFriends

如果您想要执行此操作,有两个级别的缓存看起来有点过分,您可以执行以下操作:

UIImages

UIImage *userImage = [self.imageFriends objectForKey:[NSNumber numberWithInt:user.userId]]; if (userImage) { // if the dictionary of images has it just display it cell.imageView.image = userImage; } else { cell.imageView.image = [UIImage imageNamed:@"xger86x.jpg"]; // set placeholder image BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:user.image]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSData *imageData = nil; if (fileExists){ imageData = [NSData dataWithContentsOfFile:user.image]; } else { imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:user.imageURL]]; [imageData writeToFile:user.image atomically:YES]; } if (imageData){ dispatch_async(dispatch_get_main_queue(), ^{ // UIKit, which includes UIImage warns about not being thread safe // So we switch to main thread to instantiate image UIImage *image = [UIImage imageWithData:imageData]; [self.imageFriends setObject:image forKey:[NSNumber numberWithInt:user.userId]]; UITableViewCell *lookedUpCell = [tableView cellForRowAtIndexPath:indexPath]; if (lookedUpCell){ lookedUpCell.imageView.image = image; [lookedUpCell setNeedsLayout]; } }); } }); } UIImage的一部分,而不是线程安全的。但是您可以在另一个线程上加载UIKit

答案 1 :(得分:6)

您正在异步加载图像,因此在快速滚动过程中,单元格可以更快地重复使用,然后下载图像。避免加载错误图像的一种方法是检查在加载图像时是否已经重新使用了单元格。或者在取消新单元格时取消正在进行的所有请求。

我还建议您查看AFNetworking,因为它包含UIImageView的有用类别,因此您可以执行以下操作:

[imageView setImageWithURL:[NSURL URLWithString:@"http://i.imgur.com/r4uwx.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder-avatar"]];

它还包含cancelImageRequestOperation方法,用于取消正在进行的请求。然后你的代码将如下所示:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
} else {
    [cell.imageView cancelImageRequestOperation];
}
[cell.imageView setImageWithURL:[NSURL URLWithString:user.imageURL] placeholderImage:[UIImage imageNamed:@"xger86x.jpg"]];