使用GCD加载异步UITableViewCell图像 [英] Asynchronous UITableViewCell Image Loading Using GCD

查看:127
本文介绍了使用GCD加载异步UITableViewCell图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在尝试加载Flickr Photo的UITableView列表(cs193p iOS Stanford,作业5)。为了避免UI阻塞事件,我将每个单元的缩略图下载推迟到不同的队列(但是在主队列中更新UI)。此代码不会异步加载图像,但是一旦我单击UITableViewCell行就会添加缩略图。 (见下面的截图)。知道我做错了什么吗?

I'm currently trying to load a UITableView list of Flickr Photo (cs193p iOS Stanford, assignment 5). To avoid UI blocking event, I've deferred the thumbnail download of each cell into a different queue (but do update the UI back in the main queue). This code doesn't asynchronously load the images, though does add a thumbnail once I click on of the UITableViewCell row. (see screenshots below). Any idea what i'm doing wrong?

PS:我已经看过其他一些stackoverflow问题& Apple的LazyTableImages示例,但我仍然相信这是实现理想结果的最简洁方法。

PS: I've looked already in a few other stackoverflow questions & Apple's LazyTableImages example, but I remain convinced this is the cleanest way to achieve the desired result.

谢谢!

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Photo List Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    // Configure the cell
    NSDictionary *photo = [self.photoList objectAtIndex:indexPath.row];


    if (photo != nil) {
        if ([[photo objectForKey:@"title"] length] > 0) {
            cell.textLabel.text = [photo objectForKey:@"title"];
        } else if ([[[photo objectForKey:@"description"] objectForKey:@"_content"] length] > 0) {
            cell.textLabel.text = [[photo objectForKey:@"description"] objectForKey:@"_content"];
        } else {
            cell.textLabel.text = @"Unknown";
        }
    }
    cell.imageView.image = [[UIImage alloc] initWithCIImage:nil];

    // Fetch using GCD
    dispatch_queue_t downloadThumbnailQueue = dispatch_queue_create("Get Photo Thumbnail", NULL);
    dispatch_async(downloadThumbnailQueue, ^{
        UIImage *image = [self getTopPlacePhotoThumbnail:photo];
        dispatch_async(dispatch_get_main_queue(), ^{
            if ([self.tableView.visibleCells containsObject:cell]) {
                [cell.imageView setImage:image];
            }
        });
    });
    dispatch_release(downloadThumbnailQueue);

    return cell;
}

点击一行之前

Before clicking a row

选择行后

After selecting the row

更新:对于有兴趣的人,这个是我使用的最终代码:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
  static NSString *CellIdentifier = @"Photo List Cell";
  UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

  // Configure the cell
  NSDictionary *photo = [self.photoList objectAtIndex:indexPath.row];

  if (photo != nil) {
    if ([[photo objectForKey:@"title"] length] > 0) {
        cell.textLabel.text = [photo objectForKey:@"title"];
    } else if ([[[photo objectForKey:@"description"] objectForKey:@"_content"] length] > 0) {
        cell.textLabel.text = [[photo objectForKey:@"description"] objectForKey:@"_content"];
    } else {
        cell.textLabel.text = @"Unknown";
    }
  }
  cell.imageView.image = [[UIImage alloc] initWithCIImage:nil];

  // Fetch using GCD
  dispatch_queue_t downloadThumbnailQueue = dispatch_queue_create("Get Photo Thumbnail", NULL);
  dispatch_async(downloadThumbnailQueue, ^{
    UIImage *image = [self getTopPlacePhotoThumbnail:photo];
    dispatch_async(dispatch_get_main_queue(), ^{
        UITableViewCell *cellToUpdate = [self.tableView cellForRowAtIndexPath:indexPath]; // create a copy of the cell to avoid keeping a strong pointer to "cell" since that one may have been reused by the time the block is ready to update it. 
        if (cellToUpdate != nil) {
            [cellToUpdate.imageView setImage:image];
            [cellToUpdate setNeedsLayout];
        }
    });
  });
  dispatch_release(downloadThumbnailQueue);

  return cell;
}


推荐答案

你应该致电<$ c设置缩略图后,单元格上的$ c> setNeedsLayout 。

来自Apple Doc:

From the Apple Doc:

当你想调整视图的子视图的布局时,在应用程序的主线程上调用此方法。此方法记录请求并立即返回。因为此方法不强制立即更新,而是等待对于下一个更新周期,您可以在更新任何视图之前使用它来使多个视图的布局无效。这种行为允许您将所有布局更新合并到一个更新周期,这通常会提高性能。

"Call this method on your application’s main thread when you want to adjust the layout of a view’s subviews. This method makes a note of the request and returns immediately. Because this method does not force an immediate update, but instead waits for the next update cycle, you can use it to invalidate the layout of multiple views before any of those views are updated. This behavior allows you to consolidate all of your layout updates to one update cycle, which is usually better for performance."

这篇关于使用GCD加载异步UITableViewCell图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆