Trying to load image & identifier from photo library with PhotosPicker

I'm updating an older Mac app written in Objective C and OpenGL to be a mutliplatform app in SwiftUI and Metal.

The app loads images and creates kaleidoscope animations from them.

It is a document-based application, and saves info about the kaleidoscope into the document. On macOS, it creates a security-scoped bookmark to remember the user's chosen image.

On iOS, I use a PhotosPicker to have the user choose an image from their photo library to use. I would like to get the itemIdentifier from the image they choose and save that into my document so I can use it to fetch the image when the user reloads the kaleidoscope document in the future.

However, the call to loadTransferable is returning nil for the itemIdentifier. Here is my iOS/iPadOS code:

        #if os(macOS)
            // Mac code
        #else
            PhotosPicker("Choose image", selection: $selectedItem, matching: .images)
                .onChange(of: selectedItem) {
                    Task {
                        if let newValue = selectedItem {
                            scopeState.isHEIC =  newValue.supportedContentTypes.contains(UTType.heic)
                            
                            let data = try? await newValue.loadTransferable(type: Data.self)
                            print("newValue = \(newValue)")
                            print("newValue.supportedContentTypes = \(newValue.supportedContentTypes)")
                            scopeState.selectedImageID = newValue.itemIdentifier
                            scopeState.selectedImageData = data
                        }
                    }
                }
        #endif

The debug print statements show:

newValue = PhotosPickerItem(_itemIdentifier: "9386762B-C241-4EE2-9942-BC04017E35C1/L0/001", _shouldExposeItemIdentifier: false, _supportedContentTypes: [<_UTCoreType 0x20098cd40> public.png (not dynamic, declared), <UTType 0x11e4ec060> com.apple.private.photos.thumbnail.standard (not dynamic, declared), <UTType 0x11e4ec150> com.apple.private.photos.thumbnail.low (not dynamic, declared)], _content: _PhotosUI_SwiftUI.PhotosPickerItem.(unknown context at $1e75ee3bc).Content.result(PhotosUI.PHPickerResult(itemProvider: <PUPhotosFileProviderItemProvider: 0x11d2bd680> {types = (
    "public.png",
    "com.apple.private.photos.thumbnail.standard",
    "com.apple.private.photos.thumbnail.low"
)}, _objcResult: <PHPickerResult: 0x11b18cff0>)))
newValue.supportedContentTypes = [<_UTCoreType 0x20098cd40> public.png (not dynamic, declared), <UTType 0x11e4ec060> com.apple.private.photos.thumbnail.standard (not dynamic, declared), <UTType 0x11e4ec150> com.apple.private.photos.thumbnail.low (not dynamic, declared)]

And the returned item has a nil itemIdentifier. (note the _shouldExposeItemIdentifier=false in the log of the selected item).

How do I get the itemIdentifier for the user's chosen image?

And is that valid to then fetch the asset when the user reloads their document? Is it like a security-scoped bookmark on macOS, where the itemIdentifier is like a key that gives me permission to reload the image?

If not, what do I need to do in order to reload the image the next time the user opens a saved kaleidoscope document?

If you want itemIdentifiers for the chosen items you will need to pass in the shared photo library to the PhotosPicker. There's some brief discussion of this here: https://developer.apple.com/documentation/photosui/photospickeritem/itemidentifier

If you go this route of relying the the identifier to fetch the actual image data from the photo library you will need to ensure you app has everything needed to prompt for Photo Library access. If a user selects a photo in the presented PhotosPicker it does not grant your app access to that photo form the photo library forever. More details here: https://developer.apple.com/documentation/photokit/delivering-an-enhanced-privacy-experience-in-your-photos-app

For the workflow you're describing I would generally recommend you copy the image data to your app's local storage when a user selects an image in the PhotosPicker. If you are just holding onto an itemIdentifier and relying on the PhotoLibrary to fetch that image at a later time the user may have deleted the photo from their Photo Library and be surprised that it is also gone from your application.

I'd recommend looking through the documentation here as well for the various PhotoPicker APIs as it gives some more in depth discussion around these APIs. https://developer.apple.com/documentation/photokit/selecting-photos-and-videos-in-ios

Trying to load image & identifier from photo library with PhotosPicker
 
 
Q