Photos.frameworkでiCloud保存されている画像をロードできない問題の対応

これは iOS Advent Calendar 2017 18日目の投稿です。
昨日17日目はk0mach1さんのFirebase Authentication の idToken をサーバーの認証に使い自サービスのUserと紐づけた話(iOS編)でした。

想定機能

以下のような、アプリの1機能を考えます。

Screen Shot 2017-12-18 at 18.43.56.png

  • カメラロールから画像をロードし、UICollectionViewで表示
  • 選択すると、上部のプレビューを表示
    • この時、オリジナル画像としてロードする
  • オリジナルの画像を使って、次の処理に進む

ハマりどころ

以下の複合要素でハマりました...

  • iCloud設定の iPhoneのストレージ最適化 (Optimize iPhone Strage) をオンにしている
  • オリジナルのサイズで取得するためのサイズ定数 PHImageManagerMaximumSize を指定

iCloud設定の iPhoneのストレージ最適化 (Optimize iPhone Strage) をオンにしている

以下の 設定 > iCloud > 写真 でストレージの最適化オプションが選択されている時のことです。
IMG_6074.PNG

この場合、request optionに以下を指定することで、iCloud上の写真も取得することができます。

let requestOptions = PHImageRequestOptions()
requestOptions.isNetworkAccessAllowed = true

しかし、これだけでは、次の条件の時に問題がまだ問題が残ります。
(逆に言うと、これだけで取得できていた条件もありました。)

オリジナルのサイズで取得するためのサイズ定数 PHImageManagerMaximumSize を指定

PHImageManagerMaximumSize には、以下の説明が記載されています。

// Size to pass when requesting the original image or the largest rendered image available (resizeMode will be ignored)
@available(iOS 8.0, *)
public let PHImageManagerMaximumSize: CGSize

本来の画像を取得するには、元のサイズがわからないため、この定数を指定します。

何が問題だったか

今回のような要件をきちんと満たすためには、isNetworkAccessAllowed = trueだけでなく、progressHandlerの処理も必要でした。

今回惑わされた原因は、
CollectionViewで表示している画像のように、サイズを指定してリクエストすると取得でき、サムネイル上は取得できているように見えてしまっていた点
です。

そして、ストレージの最適化の対象となっている画像は、オリジナルでロードしてみるまで、見かけ上は判別できません。

回答

ということで、解決したコードです。

let requestOptions = PHImageRequestOptions()
requestOptions.version = .current
requestOptions.deliveryMode = .highQualityFormat
requestOptions.isSynchronous = false
requestOptions.isNetworkAccessAllowed = true
requestOptions.progressHandler = { [weak self](progress, error, stop, info) in
    print("Loading image from iCloud")
}
PHImageManager.default().requestImage(for: photoAsset.asset,
                                      targetSize: PHImageManagerMaximumSize,
                                      contentMode: .aspectFill,
                                      options: requestOptions,
                                      resultHandler: { [weak self](image, _) in
                                          guard let image = image else { return }
                                          self?.selectedImage = image
})

まとめ

時間の制約のため、さらっとしかドキュメントを調べることができなかったのですが、 Photos.framework についての説明は少なく、stack overflowでも僅かな情報しか見つかりませんでした。
もし、この部分を網羅しているドキュメントを知っている方がいましたら、ぜひ教えてください。

参考

https://stackoverflow.com/questions/43114112/ios-photos-framework

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.