2

最新の SDK を使用して iOS 5.0 以降のアプリケーションを開発しています。

これは、画像を非同期的にロードするために使用するコードですUITableViewCell

- (UITableViewCell*)tableView:(UITableView *)tableView
        cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if ((groups != nil) && (groups.count > 0))
    {
        GroupCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil)
        {
            cell = [[GroupCell alloc] initWithStyle:UITableViewCellStyleDefault
                                     reuseIdentifier:CellIdentifier];
        }
        // Configure the cell...
        Group* group = [groups objectAtIndex:indexPath.row];

        cell.GroupNameLabel.text = group.Name;
        // TODO: Poner el estado.
        if (group.Photo)
            cell.GroupImageView.image = group.Photo;
        else
        {
            // download the photo asynchronously
            NSString *urlString =
                [NSString stringWithFormat:kGetGroupImageURL, [group.GroupId intValue]];
            NSURL *url = [NSURL URLWithString:urlString];

            [ImageTool downloadImageWithURL:url completionBlock:^(BOOL succeeded, UIImage *image) {
                if (succeeded)
                {
                    // change the image in the cell
                    cell.GroupImageView.image = image;

                    // cache the image for use later (when scrolling up)
                    group.Photo = image;
                }
            }];
        }

        return cell;
    }
    else
        return nil;
}

そしてローダー:

#import "ImageTool.h"

@implementation ImageTool

+ (void)downloadImageWithURL:(NSURL *)url
             completionBlock:(void (^)(BOOL succeeded, UIImage *image))completionBlock
{
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [NSURLConnection sendAsynchronousRequest:request
                                       queue:[NSOperationQueue mainQueue]
                           completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
                               if ( !error )
                               {
                                   UIImage *image = [[UIImage alloc] initWithData:data];
                                   completionBlock(YES,image);
                               } else{
                                   completionBlock(NO,nil);
                               }
                           }];
}

しかし、画像を読み込んでいるセルがまだ表示されている場合は処理しないため、うまくいかないようです。

セルがまだ表示されている場合、どのように処理できますか?

この記事を見つけましたが、実装方法がわかりません。

4

1 に答える 1

4

UITableView通常、これは、メソッドを使用してセルがまだ表示されているかどうかを確認することで処理されます。このメソッドは、そのインデックス パスのセルが表示されなくなった場合cellForRowAtIndexPath:に返します。nilこのメソッドは、同様の名前のUITableViewDataSourceメソッドと混同しないでくださいtableView:cellForRowAtIndexPath:

if (group.Photo)
    cell.GroupImageView.image = group.Photo;
else
{
    // don't forget to `nil` or use placeholder for `GroupImageView` because if
    // the cell is reused, you might see the old image for the other row momentarily
    // while the new image is being retrieved

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

    // download the photo asynchronously
    NSString *urlString =
        [NSString stringWithFormat:kGetGroupImageURL, [group.GroupId intValue]];
    NSURL *url = [NSURL URLWithString:urlString];

    [ImageTool downloadImageWithURL:url completionBlock:^(BOOL succeeded, UIImage *image) {
        if (succeeded)
        {
            dispatch_async(dispatch_get_main_queue(), ^ {
                GroupCell *updateCell = [tableView cellForRowAtIndexPath:indexPath];
                if (updateCell) 
                {
                    // change the image in the cell
                    updateCell.GroupImageView.image = image;
                }

                // cache the image for use later (when scrolling up)
                group.Photo = image;
            });
        }
    }];
}

の完了ブロックがsendAsynchronousRequestメイン キューに送信されない場合 (たとえば、メイン キューを結び付けたくない計算コストの高い処理を行う場合)、示されているようにさらに UI 更新をメイン キューにディスパッチすることができます。その上。上記のようにここか、または で実行できますdownloadImageWithURL。ただし、必ずメイン キューの UI を更新してください (同期の問題を回避するためにgroup、そこでも更新してください)。ただし、オペレーション キューのメイン キューを指定したので、これは重大な問題ではありません。

コードのコメントで指摘したように、再利用されたセルの画像を取得する場合は、GroupImageView.imageプロパティをにリセットすることも忘れないでくださいnil。そうしないと、新しい行のリクエストの進行中に、再利用されたセルの前の画像が一時的に表示されることがあります。


または、 SDWebImageUIImageViewによって提供されるようなカテゴリを使用して、これらすべて (キャッシュ管理を含む) を処理する必要があります。

余談ですが、コードでは処理されない微妙な問題、つまり低速のインターネット接続で長いテーブルビューをすばやくスクロールする問題も処理します。NSURLConnection実装では、他のセルの画像がすべて読み込まれるまで、現在表示されているセルの画像を読み込みません (一度に 5 つの同時オブジェクトしか存在できないため)。これらのUIImageViewカテゴリは通常、再利用されたセルに対する古い要求をキャンセルします。これにより、ユーザーが実際に見ている画像が UI により迅速に表示されます。

于 2013-10-23T14:54:29.187 に答える