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

xge*_*86x 6 uitableview ios

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

    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];
            });
        });
    }
Run Code Online (Sandbox Code Playgroud)

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

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

NJo*_*nes 7

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

有趣的是,你似乎在做某种UIImage缓存.将图像添加到我假设的是一个NSMutableArray名为的属性imageFriends.但是,如果您拥有该文件的本地副本,您似乎已注释掉缓存添加.您发布的代码也不会使用缓存UIImages.

虽然如果你想这样做,2级缓存似乎有点落伍,你可以这样做:

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];
               }
           }); 
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

UIImages是一部分,UIKit而不是线程安全的.但是你可以加载NSData另一个线程.


And*_*nyi 6

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

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

[imageView setImageWithURL:[NSURL URLWithString:@"http://i.imgur.com/r4uwx.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder-avatar"]];
Run Code Online (Sandbox Code Playgroud)

它还包含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"]]; 
Run Code Online (Sandbox Code Playgroud)