15

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

PS:我已经查看了其他一些 stackoverflow 问题和 Apple 的 LazyTableImages 示例,但我仍然坚信这是实现预期结果的最干净的方法。

谢谢!

- (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;
}

在单击一行之前 在单击一行之前

选择行后 选择行后

更新:对于那些感兴趣的人,这是我使用的最终代码:

- (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;
}
4

2 回答 2

15

setNeedsLayout设置缩略图后,您应该调用单元格。

来自苹果文档:

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

于 2012-09-07T04:18:25.047 回答
0

另一种解决方案(也是我用于该分配的解决方案)是在将 UIImage 分配给该 imageView 后,在单元格的 imageView 上调用 setNeedsDisplay。

所以基本上,我创建了一个名为 FlickrDownloader 的类,它封装了 FlickrFetcher 的功能(以及我的缓存代码)。FlickrDownloader 有这个方法:

(void)getImageForPhotoInfo:(NSDictionary *)photoInfo ofFormat:(FlickrPhotoFormat)format withCallback:(image_setter_callback_t)callback;

这基本上是对 FlickrFetcher 相同函数的调用,但它添加了一个在完成下载照片时调用的回调。在更新 UITableViewCell 的 imageView 的情况下,回调如下所示:

image_setter_callback_t setImage = ^(UIImage *image){
    cell.imageView.image = image;
    [cell.imageView setNeedsDisplay];
};
于 2012-09-07T04:47:14.310 回答