I am using PhotosPicker to let users select a photo. How do I retrieve the url of the selected photo?
I've tried printing out the imageSelection.itemIdentifier and got Optional("03966B05-1F51-4A20-801C-B617A2BC14DB/L0/001"), I don't know if this is related to a url path.
Here is my class using PhotosPicker, using sample code from WWDC2022.
class CreateViewModel: ObservableObject {
@Published var post: Post = Post() // Record being added to CloudKit
enum ImageState {
case empty, loading(Progress), success(Image), failure(Error)
}
@Published private(set) var imageState: ImageState = .empty
@Published var imageSelection: PhotosPickerItem? {
didSet {
if let imageSelection {
let progress = loadTransferable(from: imageSelection)
imageState = .loading(progress)
} else {
imageState = .empty
}
}
}
// Load asset data using transferable
private func loadTransferable(from imageSelection: PhotosPickerItem) -> Progress {
return imageSelection.loadTransferable(type: Image.self) { result in
DispatchQueue.main.async {
guard imageSelection == self.imageSelection else { return }
switch result {
case .success(let image?):
// Handle the success case with the image.
print("Image ID: \(imageSelection.itemIdentifier)") // Optional("03966B05-1F51-4A20-801C-B617A2BC14DB/L0/001")
self.imageState = .success(image)
case.success(nil):
// Handle the success case with an empty value.
self.imageState = .empty
case .failure(let error):
// Handle the failure case with the provided error.
print("Error image: \(error)")
self.imageState = .failure(error)
}
}
}
}
func createPost() async {
// 1. Create record object
let record = CKRecord(recordType: "Post")
// 2. Set record's fields
record.setValuesForKeys([
"title": post.title,
"caption": post.caption,
"likes": post.likes,
"size": post.keyboard.size.rawValue,
"keycaps": post.keyboard.keycaps,
"switches": post.keyboard.switches,
"case": post.keyboard.case,
"plate": post.keyboard.plate,
"foam": post.keyboard.foam
])
// Create CKAsset to store image onto CloudKit
let url = ...
record["image"] = CKAsset(fileURL: url) // Stuck! Don't know how to access url using PhotoPicker
// 3. Save to icloud (public database)
await savePost(record: record)
}
}
Here's a function I put together quickly. I tested it with videos, images, and gifs to use with QuickLook since it only accepts URLs, and it works. Best.
// MARK: - getURL
func getURL(item: PhotosPickerItem, completionHandler: @escaping (_ result: Result<URL, Error>) -> Void) {
// Step 1: Load as Data object.
item.loadTransferable(type: Data.self) { result in
switch result {
case .success(let data):
if let contentType = item.supportedContentTypes.first {
// Step 2: make the URL file name and a get a file extention.
let url = getDocumentsDirectory().appendingPathComponent("\(UUID().uuidString).\(contentType.preferredFilenameExtension ?? "")")
if let data = data {
do {
// Step 3: write to temp App file directory and return in completionHandler
try data.write(to: url)
completionHandler(.success(url))
} catch {
completionHandler(.failure(error))
}
}
}
case .failure(let failure):
completionHandler(.failure(failure))
}
}
}
/// from: https://www.hackingwithswift.com/books/ios-swiftui/writing-data-to-the-documents-directory
func getDocumentsDirectory() -> URL {
// find all possible documents directories for this user
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
// just send back the first one, which ought to be the only one
return paths[0]
}
And this is how to use it:
getURL(item: YOURPhotosPickerItem) { result in
switch result {
case .success(let url):
// Use the URL as you wish.
print(url)
case .failure(let failure):
print(failure.localizedDescription)
}
}