環境
起こること
PHPickerViewControllerを利用して画像を取得する時、インターネットに転がってるコードを参考に実装していくとこんな感じになる。
func showPicker() { var configuration = PHPickerConfiguration() configuration.filter = .any(of: [.images]) let picker = PHPickerViewController(configuration: configuration) picker.delegate = self present(picker, animated: true) } func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { picker.dismiss(animated: true) guard let itemProvider = results.first?.itemProvider else { return } let typeChecked = itemProvider.registeredTypeIdentifiers.map { itemProvider.hasItemConformingToTypeIdentifier($0) } guard !typeChecked.contains(false) else { return } guard itemProvider.canLoadObject(ofClass: UIImage.self) else { return } itemProvider.loadObject(ofClass: UIImage.self) { object, error in let image = object as? UIImage DispatchQueue.main.async { self.imageView.image = image } } }
showPicker()
を呼べばPHPickerViewControllerが表示されて、画像を1枚選択できる。その後はコードに書いてある通り UIImage
に変換して UIImageView
にセットしている。
このコードだとほとんど上手くいくが、シミュレーターで試してみると『ピンク(紫)の花の画像』だけうまく取得できない。
エラーとしてはこんな感じのものが出る
[claims] Upload preparation for claim CA6415EA-8DE0-45D8-A1CD-B090459A2EC7 completed with error: Error Domain=NSCocoaErrorDomain Code=260 "The file “version=1&uuid=CC95F08C-88C3-4012-9D6D-64A413D254B3&mode=current.jpeg” couldn’t be opened because there is no such file."
調査
調べてみると、この画像だけ registeredTypeIdentifiers
に "public.heic" も含まれていることがわかる。
print(itemProvider.registeredTypeIdentifiers) // => ["public.jpeg", "public.heic"]
シミュレーターに元々入っている他の画像は ["public.jpeg"]
なので、HEICタイプの画像かどうかが影響していそう。
試しにHEIC形式の写真をiPhoneで撮影してシミュレーターに転送してみたところ、こちらも開けなかった。
どうやらHEIC形式の画像の場合、loadObject
が利用できなさそうなので、別の方法でデータを取得する必要がありそう。
対応方法
結論としては、
preferredAssetRepresentationMode
を.current
に指定するloadObject
ではなくloadFileRepresentation
を使う
ことでHEICもJPEGも同じように取得できた。それに対応したコードは下記。
func showPicker() { var configuration = PHPickerConfiguration() configuration.filter = .any(of: [.images]) configuration.preferredAssetRepresentationMode = .current // この設定も追加が必要 let picker = PHPickerViewController(configuration: configuration) picker.delegate = self present(picker, animated: true) } func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { picker.dismiss(animated: true) guard let itemProvider = results.first?.itemProvider else { return } let typeChecked = itemProvider.registeredTypeIdentifiers.map { itemProvider.hasItemConformingToTypeIdentifier($0) } guard !typeChecked.contains(false) else { return } itemProvider.loadFileRepresentation(forTypeIdentifier: UTType.image.identifier) { (url, error) in guard let url = url else { return } guard let imageData = try? Data(contentsOf: url) else { return } DispatchQueue.main.async { self.imageView.image = UIImage(data: imageData) } } }
備考
- 表題通り実機だと問題なく動く
- シミュレーターでもうまく読み込めるHEICとそうでないのがある
- 様子を見ていると
mode=current.heic
からmode=current.jpeg
を生成しているが、これが上手く動かないことがあるっぽい
- 様子を見ていると