新生 ALAssetsLibrary
であるところの PHPhotoLibrary
ですが、まあ互換性をぶち壊したのもさることながら多少理解し難い API にもなっている所があります。
- requestImageForAsset
が二回 handler を呼ぶ
PHImageManager - requestImageForAsset:targetSize:contentMode:options:resultHandler:
こいつの resultHandler
は二回以上呼ばれます。
というのも、解像度が低い画像を先に渡して、あとから取得した解像度の高い画像を渡す、という仕様になっているようです。
想定用途は、「画像の取得には時間がかかるから、サムネイルを表示してお茶を濁してくれ」ということらしいですね。
また、二回と書きましたが取得するサイズによっては数回に渡って resultHandler
を渡す可能性があります。
というわけで、画像を取ってきて xx する、といった処理にこいつを使うと想定外の動作をする可能性があります。注意が必要です。
冪等な操作でも、例えばフィルタ等重い処理が複数回走るとアプリの体験を損なう可能性があります。
これを防止する方法としては、次の 3 つがあります。
解決策1 - info
の PHImageResultIsDegradedKey
を見る
resultHandler
の第二引数である info
に、 PHImageResultIsDegradedKey
で BOOL
が入っているのでこいつを見ます。
コードとしては、
[[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 - PHImageRequestOptions
で deliveryMode
を設定する
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
をぶち壊しになられた事案について書きたいと思います。
参考資料
- Image Result Info Keys - PHImageManager Class Reference : https://developer.apple.com/library/ios/documentation/Photos/Reference/PHImageManager_Class/index.html#//apple_ref/doc/constant_group/Image_Result_Info_Keys