【问题标题】:UITableView with asynchronous loading of image in cells - images keep changing on slow connectionUITableView 在单元格中异步加载图像 - 图像在慢速连接时不断变化
【发布时间】:2015-01-11 19:21:29
【问题描述】:

我在表格视图中异步加载图像。在慢速连接时,单元格中的图像会不断闪烁/变化(我假设它来自重复使用单元格)。我遵循了其他一些相关问题的建议,包括:

  • 缓存图像
  • 设置占位符图片

在正常连接下工作正常,但在 EDGE 和慢速网络上,问题仍然存在。我想知道是否是网络请求备份的全局队列?如果是这样,我该如何解决?

这是我的代码:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // get the data for this photo post
    NSDictionary *data = [self.streamPhotosData objectAtIndex:indexPath.row];

    static NSString *CellIdentifier = @"StreamPhotoTableViewCell";
    __block StreamPhotoTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"StreamPhotoTableViewCell"];

    if (cell == nil) {
        cell = [[StreamPhotoTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }

    cell.delegate = self;

    // check if image in cache, else cache it
    if ([[[GlobalCaches getCurrentInstance] photoCache] objectForKey:[data objectForKey:@"photoGuid"]] != nil) {
        // cache hit
        cell.photoImageView.image = [[[GlobalCaches getCurrentInstance] photoCache] objectForKey:[data objectForKey:@"photoGuid"]];
    } else {
        // set a placeholder image
        cell.photoImageView.image = [UIImage imageNamed:@"placeholder.png"];

        // download the image asynchronously
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
            UIImage *downloadedImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[data objectForKey:@"url"]]]];

            if (downloadedImage) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    cell.photoImageView.image = downloadedImage;

                    // update cache
                    [[[GlobalCaches getCurrentInstance] photoCache] setObject:downloadedImage forKey:[data objectForKey:@"photoGuid"]];
                });
            }
        });

    }

    return cell;
}

【问题讨论】:

  • 当您调度回主队列时,不要使用现有的cell 引用,因为它可能已被滚动出屏幕并被重复使用。使用 indexPath 使用 UITableView cellforRowAtIndexPath: 方法查找正确的单元格。

标签: ios objective-c cocoa-touch


【解决方案1】:

我曾经遇到过类似的问题。

为什么会这样? 假设您在 cellForRow 中的第 1 行,此图像不在缓存中,因此您正在下载它。同时,您滚动 tableView,假设您现在位于第 8 行的 cellForRow 中,这是同一个单元格实例。 假设现在你有这个图像在缓存中,所以你只是设置没有时间偏移的图像,在单元格有正确的图像之后,第 1 行的图像就准备好了,记住它是一样的cell 实例,因此图像被替换。 当然这只是一个例子。

您可以尝试“记住”您从哪一行开始下载图像,在开始下载之前设置一个“beforeTag”,然后检查它是否是相同的 indexPath。行

    NSInteger beforeTag = indexPath.row;

    // download the image asynchronously
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
        UIImage *downloadedImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[data objectForKey:@"url"]]]];

        if (downloadedImage) {
            dispatch_async(dispatch_get_main_queue(), ^{

                if (indexPath.row == beforeTag) {
                    cell.photoImageView.image = downloadedImage;
                }

                // update cache
                [[[GlobalCaches getCurrentInstance] photoCache] setObject:downloadedImage forKey:[data objectForKey:@"photoGuid"]];
            });
        }
    });

另外,我会将这一行放在您的自定义单元格中的 prepareForReuse 中:

cell.photoImageView.image = [UIImage imageNamed:@"placeholder.png"];

每次重用 UITableViewCell 时都会调用此方法,如果单元格已存在,则会在您“dequeueReusableCellWithIdentifier”之后调用。并且可以始终放置 placeHolder 图像,如果图像在缓存中,您将不会注意到这个占位符。

希望对你有帮助

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-18
    • 1970-01-01
    相关资源
    最近更新 更多