GarySabo
GarySabo

Reputation: 6680

Saving a reference to an image in camera roll to recall later in app?

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

Answers (2)

YodagamaHeshan
YodagamaHeshan

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

impression7vx
impression7vx

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

Related Questions