Reputation: 6680
I'm trying to let the user take or select an image in an ImagePickerController
, and I want to save a reference (as efficiently as possible) in my app to recall when the app loads again. Is saving the image's file URL the best approach for this?
import UIKit
import SwiftUI
struct ImagePicker: UIViewControllerRepresentable {
var sourceType: UIImagePickerController.SourceType = .photoLibrary
@Binding var selectedImage: UIImage
@Environment(\.presentationMode) private var presentationMode
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
let imagePicker = UIImagePickerController()
imagePicker.allowsEditing = false
imagePicker.sourceType = sourceType
imagePicker.delegate = context.coordinator
return imagePicker
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
final class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var parent: ImagePicker
init(_ parent: ImagePicker) {
self.parent = parent
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
parent.selectedImage = image
}
if let imgUrl = info[UIImagePickerController.InfoKey.imageURL] as? URL{
let imgName = imgUrl.lastPathComponent
let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first
let localPath = documentDirectory?.appending(imgName)
let image = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
let data = image.pngData()! as NSData
data.write(toFile: localPath!, atomically: true)
//let imageData = NSData(contentsOfFile: localPath!)!
let photoURL = URL.init(fileURLWithPath: localPath!)//NSURL(fileURLWithPath: localPath!)
print(photoURL)
//TODO save this url in my app as a reference to look up
}
parent.presentationMode.wrappedValue.dismiss()
}
}
}
Upvotes: 0
Views: 270
Reputation: 6500
URL of image of camera roll may change , better way is to save your image to filesystem in the app sandbox and the you can save given name or something to retrieve it when u needed back
//MARK: save and retrive Images
extension UIImage {
func saveImage(imageName: String) {
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
let fileName = imageName
let fileURL = documentsDirectory.appendingPathComponent(fileName)
guard let data = self.jpegData(compressionQuality: 1) else { return }
//Checks if file exists, removes it if so.
if FileManager.default.fileExists(atPath: fileURL.path) {
do {
try FileManager.default.removeItem(atPath: fileURL.path)
print("Removed old image")
} catch let removeError {
print("couldn't remove file at path", removeError)
}
}
do {
try data.write(to: fileURL)
} catch let error {
print("error saving file with error", error)
}
}
static func loadImageFromDiskWith(fileName: String) -> UIImage? {
let documentDirectory = FileManager.SearchPathDirectory.documentDirectory
let userDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let paths = NSSearchPathForDirectoriesInDomains(documentDirectory, userDomainMask, true)
if let dirPath = paths.first {
let imageUrl = URL(fileURLWithPath: dirPath).appendingPathComponent(fileName)
let image = UIImage(contentsOfFile: imageUrl.path)
return image
}
return nil
}
static func removeImage(fileName: String){
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
let fileURL = documentsDirectory.appendingPathComponent(fileName)
if FileManager.default.fileExists(atPath: fileURL.path) {
do {
try FileManager.default.removeItem(atPath: fileURL.path)
print("Removed image")
} catch let removeError {
print("couldn't remove file at path", removeError)
}
}
}
}
Usage
yourImage.saveImage(imageName: "imageNameToSave")//<-save
UIImage.loadImageFromDiskWith(fileName: "ImageNameToRetrive")//<-retrive
UIImage.removeImage(fileName: "ImageNameToRemove")//<-remove
Upvotes: 1
Reputation: 1863
Edit:
You can definitely do FileManager
as well, it truly depends on how many files you will be saving, and to where you want to save them. If it is a measly 1 file, that doesn't need to be secured and is public to the app, UserDefaults
is the way to go. If you want to add a bit more control of that file, FileManager
would be the way to go.
UserDefaults
is your way to go to store locally.
Store Image Data
func locallyStoreImgData(image: UIImage, key:String) {
if let pngRepresentation = image.pngData() {
UserDefaults.standard.set(pngRepresentation, forKey: key)
}
else {
//Was unable to create png representation
}
}
Retrieve Image Data
func obtainImg(key:String) -> UIImage? {
if let imageData = UserDefaults.standard.object(forKey: key) as? Data,
let image = UIImage(data: imageData) {
return image
}
return nil
}
Use Case
locallyStoreImgData(image: myImage, key: "myImageKey")
if let image = obtainImg(key: "myImageKey") {
//Do something with image
}
else {
//Was unable to recreate image
}
Upvotes: 0