PHPickerViewController fails to load image

3k Views Asked by At

I have been trying to load an image from the photo library on a swifui app. I am running Xcode 13.2.1 and building IOS 15.2 My code is as below


    @Binding var image: UIImage?

    func makeUIViewController(context: Context) -> PHPickerViewController {

        var config = PHPickerConfiguration()

        config.filter = .images

        config.selectionLimit = 1

        config.preferredAssetRepresentationMode = .compatible

        let controller = PHPickerViewController(configuration: config)

        controller.delegate = context.coordinator

        return controller

    }

    func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) { }

    func makeCoordinator() -> Coordinator {

        Coordinator(self)

    }
    // Use a Coordinator to act as your PHPickerViewControllerDelegate

    class Coordinator: NSObject, PHPickerViewControllerDelegate {
        private let parent: PhotoPicker

        init(_ parent: PhotoPicker) {

            self.parent = parent

        }
        func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {

            picker.dismiss(animated: true)

            print(results)
            guard !results.isEmpty else {
                return
            }

            guard let itemProvider = results.first?.itemProvider else { return }

            print("Invoking getPhoto")

            self.getPhoto2(from: itemProvider)

            //parent.didFinishPicking(!results.isEmpty)

        }

        private func getPhoto2(from itemProvider: NSItemProvider) {

            print("getPhoto")
         
            if itemProvider.canLoadObject(ofClass: UIImage.self) {

                itemProvider.loadObject(ofClass: UIImage.self) { image, error in

                    self.parent.image = image as? UIImage

                    print("Loaded Image \(error)")

                }

            }

        }
}
}

On the console I see the following error

022-01-27 00:40:01.485085-0500 Vescense[3174:884964] [Picker] Showing picker unavailable UI (reason: still loading) with error: (null)

Further when I print the result I see

[PhotosUI.PHPickerResult(itemProvider: <PUPhotosFileProviderItemProvider: 0x2818fc980> {types = (

    "public.jpeg",

    "public.heic"

)}, assetIdentifier: nil)]

It doesn't appear like the error on loadObject has a value. And it's suspicious that assetIdentifier is nil.

Any thoughts on what I might be missing here would be most helpful.

UPDATE:

I tried using loadFileRepresentation instead.

itemProvider.loadFileRepresentation(forTypeIdentifier: UTType.jpeg.identifier) { (url, error) in
                guard let url = url else {
                    print("Failed to load url")
                    return
                }

And this time I get the following error on the console.

  Error copying file type public.jpeg. Error: Error Domain=NSItemProviderErrorDomain Code=-1000 "Cannot load representation of type public.jpeg" UserInfo={NSLocalizedDescription=Cannot load representation of type public.jpeg, NSUnderlyingError=0x600001d26430 {Error Domain=NSCocoaErrorDomain Code=4101 "Couldn’t communicate with a helper application." UserInfo={NSUnderlyingError=0x600001dbcb70 {Error Domain=PHAssetExportRequestErrorDomain Code=0 "The operation couldn’t be completed. (PHAssetExportRequestErrorDomain error 0.)" UserInfo={NSLocalizedDescription=The operation couldn’t be completed. (PHAssetExportRequestErrorDomain error 0.), NSUnderlyingError=0x600001dbca80 {Error Domain=PAMediaConversionServiceErrorDomain Code=2 "The operation couldn’t be completed. (PAMediaConversionServiceErrorDomain error 2.)" UserInfo=0x600001398e60 (not displayed)}}}}}}
1

There are 1 best solutions below

0
dsplatonov On

Try use another function to load object - loadDataRepresentation.

If I understand correctly, you chose HDR-photo. In that case itemProvider has 2 registeredTypeIdentifiers: public.jpeg, public.heic. I found that you can load image data using second typeIdentifier (public.heic). Here is my code for example:

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
    picker.dismiss(animated: true)
    itemProviders = results.map(\.itemProvider)
    
    itemProviders.forEach {
        guard let typeIdentifier = $0.registeredTypeIdentifiers.first,
              let utType = UTType(typeIdentifier) else { return }
        
        var secondTypeIdentifier: String?
        if $0.registeredTypeIdentifiers.count > 1 {
            secondTypeIdentifier = $0.registeredTypeIdentifiers[1]
        }
        
        if utType.conforms(to: .image) {
                $0.loadDataRepresentation(forTypeIdentifier: secondTypeIdentifier ?? typeIdentifier) { [weak self] data, error in
                guard let self, let data, let image = UIImage(data: data) else { return }
                // image loaded, then do your staff
        }
    }
}