LoginSignup
29
30

More than 5 years have passed since last update.

【iOS】UITableViewCellに設置したUIImageViewに非同期に画像を読込む

Last updated at Posted at 2013-11-27

Instagramとかの写真共有アプリでやってるやつです。

最初はGCDを使っていたのですが、どうも上手く行きませんでした。
別スレッドで実行している間にUITableViewがスクロールされてしまうと
同一インスタンスのUITableViewCellに対して、複数のスレッドが同時に実行されてしまってうまくいきませんでした。

もちろんちゃんと制御すれば、GCDでも出来るのでしょうが諦めてしまいました。

で、使ったのが NSBlockOperation です。
NSBlockOperationならスレッドのキャンセルもできるので、うまくいくんじゃないだろうか、と。

以下の、setPost関数はUITableViewCellを継承した自作クラスのPublic関数です。
UITableViewを管理しているUIViewController内のcellForRowAtIndexPath内で呼んでいます。

- (void)setPost{
    _photoImageView.image = nil;

    [self setPhotoImage];

    [self setNeedsLayout];
}

setPost:関数内の[self setPhotoImage]関数内でイメージの取得処理を行っています。

- (void)setPhotoImage
{
    //Queueを作成
    if (!_queue){
        _queue = [[NSOperationQueue alloc] init];
    }

    //既に実行されているスレッドがある場合はキャンセルする
    [_queue cancelAllOperations];

    //既にキャッシュされている画像なら表示して終了
    UIImage* image = //①画像のキャッシュ管理クラスから画像を取得
    if( image ){
        [_photoImageView setImage:image];
        return;
    }

    //まだキャッシュされていない画像は別スレッドで取得する
    NSBlockOperation *operation = [[NSBlockOperation alloc] init];
    __weak NSBlockOperation *weakOperation = operation; // 循環参照を避ける
    __weak PostCell* weakSelf = self;
    [operation addExecutionBlock:^{

        NSData* imageData = //②Web上からNSDataを取得

        UIImage* image = [UIImage imageWithData: imageData];

        //③取得した画像をキャッシュする
        //hogehoge

        //メインスレッドでUIImageViewにイメージをセットする
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{

            //Queueがキャンセルされていたら画像を設定せずに終了
            if (weakOperation.isCancelled) return;

            //UIImageViewに画像をセット
            [_photoImageView setImage:image];

            [weakSelf setNeedsLayout];
        }];
    }];

    [_queue addOperation:operation];
}

setPhotoImage関数内では以下のことを行っています。
1.NSOperationQueueを生成

2.スレッドのキャンセル

3.既に画像をキャッシュしていれば、キャッシュからイメージを取り出してUIImageViewにセットする。(キャッシュがあればここで終了)

4.画像を取得するNSBlockOperationを作成
4−1.Web上から画像データ(ここではNSData)を取得する
4−2.NSDataからUIimageに変換する
4−3.[NSOperationQueue mainQueue]を使って、メインスレッドのBlockを作成する
4−3−1.Queueがキャンセルされている場合は、イメージをセットしないで終了
4−3−2.Queueがキャンセルされていなければ、UIImageViewにイメージをセットする

5.4で作成したNSBlockOperationをQueueに追加する

Instagramみたいなことをやろうとしていたので
実際のコードには他にも色々と書いていますが色々と省略してしまっています。

このやり方が正しいのかは分かりませんが、とりあえずやりたいことは実現できました。

29
30
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
29
30