PHImageManager - requestImageForAsset が二回 handler を呼ぶ事案

  • 62
    いいね
  • 2
    コメント
この記事は最終更新日から1年以上が経過しています。

新生 ALAssetsLibrary であるところの PHPhotoLibrary ですが、まあ互換性をぶち壊したのもさることながら多少理解し難い API にもなっている所があります。

- requestImageForAsset が二回 handler を呼ぶ

PHImageManager - requestImageForAsset:targetSize:contentMode:options:resultHandler: こいつの resultHandler は二回以上呼ばれます。

というのも、解像度が低い画像を先に渡して、あとから取得した解像度の高い画像を渡す、という仕様になっているようです。
想定用途は、「画像の取得には時間がかかるから、サムネイルを表示してお茶を濁してくれ」ということらしいですね。

また、二回と書きましたが取得するサイズによっては数回に渡って resultHandler を渡す可能性があります。

というわけで、画像を取ってきて xx する、といった処理にこいつを使うと想定外の動作をする可能性があります。注意が必要です。
冪等な操作でも、例えばフィルタ等重い処理が複数回走るとアプリの体験を損なう可能性があります。

これを防止する方法としては、次の 3 つがあります。

解決策1 - infoPHImageResultIsDegradedKey を見る

resultHandler の第二引数である info に、 PHImageResultIsDegradedKeyBOOL が入っているのでこいつを見ます。
コードとしては、

[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:size contentMode:PHImageContentModeDefault options:nil resultHandler:^(UIImage *result, NSDictionary *info) {
    BOOL isDegraded = [info[PHImageResultIsDegradedKey] boolValue];
    if (isDegraded == YES) { return; }

    // なんかする
}];

解決策2 - PHImageRequestOptionsdeliveryMode を設定する

Option の deliveryMode でこれを制御しているらしいので、こいつを PHImageRequestOptionsDeliveryModeHighQualityFormat に設定すれば必ず指定したサイズの画像を持ってきてくれるようになります。

コードとしては

PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;

[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:size contentMode:PHImageContentModeDefault options:options resultHandler:^(UIImage *result, NSDictionary *info) {
    // なんかする
}];

解決策3 - - requestImageDataForAsset を使う

- requestImageDataForAsset:options:resultHandler: は今の所一回しか呼ばないような感じなので、こっちを使うと変に悩みません。ただしサイズの指定は出来ません。

まとめ

次は Apple 様が ALAssetsLibrary をぶち壊しになられた事案について書きたいと思います。

参考資料