2

テーブルを表示しています。各行には、URLから読み込まれた画像アイコンがあります。

画像を同期的にダウンロードするとUIがブロックされるため、グランドセントラルディスパッチを介して非同期で実装しました。

私の問題は、上下にスクロールすると、セルが再利用されているため、誤った画像が表示されることです。

これが発生している理由は推測できます。これは、再利用されたセルが画像を更新するため、以前のセルに新しくダウンロードされた間違った画像が含まれるようになるためです。これを解決するための理想的な方法は何でしょうか?

これが私のコードです。

ダウンロードした画像ごとに、「ImageStore」というシングルトンクラスに保存しています。

// set the data for each cell - reusing the cell
- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"];

   if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
                                      reuseIdentifier:@"UITableViewCell"];
    }

    // setting the image for each cell
    // first check if there is UIImage in the ImageStore already
    NSString *imageUrl = [obj objectForKey:@"image"];
    if (imageUrl) {
      if ([[ImageStore sharedStore] imageForKey:imageUrl]) {

        [[[tableView cellForRowAtIndexPath:indexPath] imageView] setImage:[[ImageStore sharedStore] imageForKey:imageUrl]];
      } else {

        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
    dispatch_async(queue, ^{
      UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:
      [NSURL URLWithString:[obj objectForKey:@"image"]]]];
      dispatch_sync(dispatch_get_main_queue(), ^{
        [[ImageStore sharedStore]setImage:image forKey:imageUrl];
        [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]withRowAnimation:UITableViewRowAnimationNone];

            [[[tableView cellForRowAtIndexPath:indexPath] imageView] setImage:image];
      });
    });
      }
    }
    return cell;
}
4

4 に答える 4

4

これを試して:

NSString *imageUrl = [obj objectForKey:@"image"];
if (imageUrl) {
  if ([[ImageStore sharedStore] imageForKey:imageUrl]) {
    [[cell imageView] setImage:[[ImageStore sharedStore] imageForKey:imageUrl]];
  } else {
  dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
  dispatch_async(queue, ^{
     UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:
     [NSURL URLWithString:[obj objectForKey:@"image"]]]];
  dispatch_sync(dispatch_get_main_queue(), ^{
     [[cell imageView] setImage:image];
     [cell setNeedsLayout];
  });
  });
}

編集:テーブルビューの遅延読み込みについては、このgrand-central-dispatch-for-ios-lazy-loadingを確認してください

于 2012-12-27T12:23:21.067 に答える
2

見てみましょうAFNetworking...彼らはネットワークコールバックの扱いを簡単にします!!! は更新を続けていて、そうではないので、お勧めAFNetworkingします...彼らはちょっと開発をやめました。ASIHTTPRequestAFNetworkingASIHTTPRequest

AFNetworking画像を非同期的にダウンロードするために使用する方法の例を次に示します。

NSDictionary * object = [self.array objectAtIndex:indexPath.row];
NSDictionary * image = [object valueForKey:@"image"];
NSString *imageUrl = [image valueForKeyPath:@"url"];
NSURL *url = [NSURL URLWithString:imageUrl];
[cell.imageView setImageWithURL:url placeholderImage:[UIImage imageNamed:@"empty-profile-150x150.png"]];

メソッドは、私がこれsetImageWithURL: placeholderImage:を行うために使用したものです...複数のメソッドとコード行ではなく、この行ですべてを達成します。

このコード行全体が、やりたいことを正確に実行します。ホイールを再作成する必要は本当にありません:)。下位レベルのプログラミングを行って、内部で実際に何が起こっているのかを実際に理解することは役に立ちます。

リンクを表示してライブラリをダウンロードし、それを使用する方法の例をさらに表示します... 真剣に、スレッドと GCD についてそれほど心配する必要がないので、あなたの人生はずっと楽になります。

AFネットワーキングのデモ

私はコードに飛び込んでいませんがAFNetworking、画像をセルにロードするときに私のアプリケーションはBUTTERのように動作します。それは素晴らしいですね:)

ああ、ここに次のドキュメントがありますAFNetworking: AFNetworking Documentation

于 2013-08-24T21:30:24.197 に答える
2

Prince Answer から少し変更

NSString *imageUrl = [obj objectForKey:@"image"];

if (imageUrl) 
{
  if ([[ImageStore sharedStore] imageForKey:imageUrl]) 
  {
      //This condition means the current cell's image has been already downloaded and stored. So set the image to imageview
      [[cell imageView] setImage:[[ImageStore sharedStore] imageForKey:imageUrl]];
  } 
  else 
  {
      //While reusing this imageView will have previous image that will be visible till the image is downloaded. So i am setting this image as nil.
      [[cell imageView] setImage:nil]; 

      dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
      dispatch_async(queue, ^{

         //Called Immediately.
         UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:
         [NSURL URLWithString:[obj objectForKey:@"image"]]]];
         dispatch_sync(dispatch_get_main_queue(), ^{

           //Called when the image is downloaded
           //Store in any external object. So that next time reuse this will not be downloaded
           [[ImageStore sharedStore]setImage:image forKey:imageUrl];
           //Also set the image to the cell
           [[cell imageView] setImage:image];
           [cell setNeedsLayout];
        });
     });
  }
}
于 2012-12-27T12:50:13.137 に答える
0

私もこの行動に気づきました。

私が見つけた唯一の一般的な解決策は、セルの再利用を無効にすることです。

于 2012-12-27T12:32:34.403 に答える