15

現在、Flickr Photo(cs193p iOS Stanford、割り当て5)のUITableViewリストを読み込もうとしています。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サムネイルを設定した後、セルを呼び出す必要があります。

Apple Doc から:

「ビューのサブビューのレイアウトを調整する場合は、アプリケーションのメイン スレッドでこのメソッドを呼び出します。このメソッドは要求を記録し、すぐに戻ります。このメソッドは即時の更新を強制するのではなく、次の更新を待機するためです。複数のビューが更新される前に、複数のビューのレイアウトを無効にするために使用できます。この動作により、すべてのレイアウトの更新を 1 つの更新サイクルにまとめることができ、通常はパフォーマンスが向上します。

于 2012-09-07T04:18:25.047 に答える
0

別の解決策 (およびその割り当てに使用したもの) は、UIImage をその imageView に割り当てたら、セルの imageView で setNeedsDisplay を呼び出すことです。

基本的に、FlickrFetcher の機能 (およびキャッシュ コード) をまとめた FlickrDownloader というクラスを作成しました。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 に答える