在相机胶卷中保存对图像的引用以便稍后在应用程序中调用?

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

我试图让用户在 ImagePickerController 中拍摄或 select 图像,并且我想在我的应用程序中保存一个参考(尽可能高效)以便在应用程序再次加载。保存图像文件 URL 是最好的方法吗?

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()
        }
    }
}

编辑: 你当然也可以做 FileManager,这真的取决于你要保存多少文件,以及你想保存它们的位置。如果它是一个只有 1 个文件的文件,则不需要保护并且对应用程序来说是 public,UserDefaults 是可行的方法。如果您想对该文件添加更多控制权,FileManager 将是您的最佳选择。

UserDefaults 是您前往本地商店的方式。

存储图像数据

func locallyStoreImgData(image: UIImage, key:String) {
    if let pngRepresentation = image.pngData() {
        UserDefaults.standard.set(pngRepresentation, forKey: key)
    }
    else {
        //Was unable to create png representation
    }
}

检索图像数据

func obtainImg(key:String) -> UIImage? {
    if let imageData = UserDefaults.standard.object(forKey: key) as? Data, 
        let image = UIImage(data: imageData) {
        return image
    }
    return nil
}

用例

locallyStoreImgData(image: myImage, key: "myImageKey")

if let image = obtainImg(key: "myImageKey") {
    //Do something with image
}
else {
    //Was unable to recreate image
}

URL 相机胶卷图像可能会改变,更好的方法是将图像保存到应用程序沙箱中的文件系统,您可以保存给定名称或其他名称以在需要时检索它

//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)
            }
        }
    }
    
}

用法

yourImage.saveImage(imageName: "imageNameToSave")//<-save
UIImage.loadImageFromDiskWith(fileName: "ImageNameToRetrive")//<-retrive
UIImage.removeImage(fileName: "ImageNameToRemove")//<-remove