This is a late answer, but hopefully it will help someone else.
Yes, it is possible. You can select photos using a PHPickerViewController
to get a PHPickerResult
, which has a assetIdentifier
attribute. The assetIdentifier
persistently and uniquely identifies the photo. When you want to load the image, read the saved assetIdentifier
and use PHAsset.fetchAssets()
to retrieve the asset and then use PHImageManager.requestImage()
to get the UIImage
. In this way, all that you need to store in your app is the assetIdentifier
, not the image data.
Here is some example code (for iOS15) for selecting one photo and getting the assetIdentifier
:
import PhotosUI
import SwiftUI
struct PhotoPicker: UIViewControllerRepresentable {
@Environment(\.dismiss) var dismiss
@Binding var assetIdentifier: String?
typealias UIViewControllerType = PHPickerViewController
func makeUIViewController(context: Context) -> PHPickerViewController {
var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
configuration.selectionLimit = 1
configuration.filter = .images
let picker = PHPickerViewController(configuration: configuration)
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {
// Do nothing.
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UINavigationControllerDelegate, PHPickerViewControllerDelegate {
let parent: PhotoPicker
init(_ parent: PhotoPicker) {
self.parent = parent
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
parent.dismiss()
// Only 1 image can be selected, so ignore any additional elements.
guard let result = results.first else {
return
}
parent.assetIdentifier = result.assetIdentifier
}
}
}
To use it: PhotoPicker(assetIdentifier: $assetIdentifier)
And then to retrieve the image from the assetIdentifier
use:
import Photos
import SwiftUI
struct LoadedImageView: View {
@State var assetIdentifier: String
@State private var image: Image? = nil
var body: some View {
VStack {
if let image = image {
image
.resizable()
.aspectRatio(contentMode: .fit)
}
}
.onAppear(perform: loadImage)
}
func loadImage() {
let fetchResults: PHFetchResult<PHAsset> =
PHAsset.fetchAssets(withLocalIdentifiers: [assetIdentifier], options: nil)
guard let asset: PHAsset = fetchResults.firstObject else {
return
}
let manager = PHImageManager()
manager.requestImage(for: asset, targetSize: PHImageManagerMaximumSize,
contentMode: .aspectFit, options: nil) { (uiImage, _) in
if let uiImage = uiImage {
self.image = Image(uiImage: uiImage)
}
}
}
}