0

I can't find much documented regarding the PHPickerViewControllerDelegate didFinishPicking function using async await and I'm not sure I understand how to use the NSItemProvider. Here is my delegate code:

    func picker( _ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]){
    for result in results {
        Task {
            if result.itemProvider.hasItemConformingToTypeIdentifier(UTType.image.identifier) {
                do {
                    let url = try await result.itemProvider.loadItem(forTypeIdentifier: UTType.image.identifier) as! URL
                    print(url.description)
                    let data = try Data(contentsOf: url)
                    let image = UIImage(data: data)
                }
                catch {
                    print(error)
                }
            }
        }
    }
}

When used in the simulator the ItemProvider returns a URL but the data content of that URL is empty. How do I grab the image from the ItemProvider? Thanks

3
  • If you want the data then I would use loadDataRepresentation instead of loadItem. Commented Mar 1, 2023 at 22:18
  • loadDataRepresentation is not available with async/await which I would prefer. What exactly does loadItem return? I don't necessarily need data, just the image and (if possible) metadata. Commented Mar 3, 2023 at 18:59
  • It's a shame only loadItem comes in the async form. To me that's the least clear method since there's no way to know what it's going to return. Commented Mar 3, 2023 at 19:34

1 Answer 1

0

As you've been told in a comment, it's a much better idea to use loadDataRepresentation here. As you've said, there is no async version of loadDataRepresentation — but you can write one by extending NSItemProvider:

import Foundation
import UniformTypeIdentifiers

extension NSItemProvider {
    /// Injected method that abstracts image data loading and makes it async/await.
    /// - Returns: The data.
    func loadImageData() async throws -> Data {
        enum ImageLoadingError: Error {
            case unknown
        }
        return try await withCheckedThrowingContinuation { continuation in
            self.loadDataRepresentation(forTypeIdentifier: UTType.image.identifier) { data, error in
                if let data {
                    continuation.resume(returning: data)
                } else {
                    continuation.resume(throwing: error ?? ImageLoadingError.unknown)
                }
            }
        }
    }
}

Now your PHPickerViewControllerDelegate method can call that, like this:

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
    picker.dismiss(animated: true) {
        Task { @MainActor in
            guard let result = results.first else { return }
            let provider = result.itemProvider
            let data = try await provider.loadImageData()
            // do something with the data here
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.