某Web系の会社の画像投稿系SNSサービスでエンジニアリングをしています。
今まで面倒でqiitaを書いてこなかったのですが、これから知見の整理として気が向いたら書いていこうと思います。
カメラロールからPHImageManagerを使ってカメラロールの画像を取得できない場合がある。
iOS11がリリースされてから、カメラロールから画像が選択できないなどの声が多くなってきました。
iOS11のリリース以前もいくつかこういったユーザさんの声はあったのですが、iOS11から現象が多くなりました。
はじめは、カメラロールに大量に画像があることが問題なのか?と考えその線で調査していたのですが
PHImageManagerのロードをページングしたり、端末の空き容量がほぼないとアラートを出してストレージの残容量を確保していただいたりしていましたが、全くの的外れでした。
以下で、原因から解決策を解説していきます。
原因
iCloudフォトライブラリが原因でした。

上のように、「iCloudフォトライブラリ」を有効にしていて、「iPhoneのストレージを最適化」を有効にしていると
起こりやすいです。
何が起きていたか
- iCloudフォトライブラリを有効にしている
この状態にすると、カメラロールの画像の実データが端末に存在せず、サムネイルのみ保持している状態が起こりうる状態になります。
ただ、これだけだとそんなにすぐに現象は発生しないので、以下のいずれかの状況が並行して起きている可能性が高いです。
- ストレージが圧迫気味
- 同じiCloudアカウントを複数の端末で使っている
ストレージが圧迫されていると、古いものから優先的に画像の実データをiCloudに飛ばされます。
また、同じiCloudアカウントを複数の端末で使っていて、別の端末で写真を撮影した場合にサムネイルだけ端末に存在する状況もあります。
なんでiOS11からこの現象が増えたの?
おそらく、iOS11からiCloudフォトライブラリを有効にするようにiOSのガイドが仕向けているのでは?と言う結論に至りました。
困ったものですね...
実はこの現象なかなか再現させるのに苦労して、同じチームのデバッグ力がすんごい人に見つけてもらいました!
感謝!!
解決策
PHImageRequestOptionsのisNetworkAccessAllowedを有効にする。
これをしないと、端末に画像のオリジナルがない場合は取得することができません。
(今まで気づかなかったw)
let options = PHImageRequestOptions()
options.isNetworkAccessAllowed = true
// open var isNetworkAccessAllowed: Bool // if necessary will download the image from iCloud (client can monitor or cancel using progressHandler). Defaults to NO (see start/stopCachingImagesForAssets)
PHImageManager.default().requestImage(for: asset, targetSize: imageSize, contentMode: .aspectFit, options: options, resultHandler: {
...
})
おまけ
iCloudに画像の実データがある時は、画像取得に時間がかかるので、取得できるまではサムネイルを表示したりするといいですね。
PHImageManager.default().requestImage(for: asset, targetSize: imageSize, contentMode: .aspectFit, options: options, resultHandler: {
if let degraded = info?[PHImageResultIsDegradedKey] as? NSNumber, !degraded.boolValue {
// NOTE: - 指定したサイズの画像が取得できます
} else {
// NOTE: - サムネイルが取得できます。(呼ばれない時もある)
}
})
requestIdなるものが帰ってくるので、非同期で実装していい感じなUXを提供したいところです。