Search code examples
swiftdirectorysaverealmjpeg

Saving image to .documentsDirectory, and as a String to store path in local Realm


I'm attempting to save (parse?) an image Path to my realm. To do that I attempting to save the image as jpegData into the documentDirectory.

The images I am saving do not need to be saved into the users photo library, only to be referenced and displayed in the app itself.

First off, I'm not certain if I am taking the right approach for this. Please direct me to the most appropriate solution for saving images locally.

I've seen only a handful of websites, Stack Overflow questions and hardly any videos, so something tells me there is a more efficient method to accomplish this. Saving Picked Image to CoreData, How to put an image in a Realm database? and how to use writeToFile to save image in document directory? led me to attempt to save the image into the directory, particularly the final SO Question.

I have the following code, but am receiving the error "Value of type 'MyViewControllerName' has no member jpegData" Any ideas how I can solve this error or adapt my code to allow it to save the image?

The image I am trying to save, once selected from Photo Library or Camera is located in selectedImageView.

I've changed the self.jpegData to UIImage.jpegData, selectedImageView.jpegData and to UIImageView.jpegData getting hosts of errors, including Instance member 'jpegData' cannot be used on type 'UIImage'; did you mean to use a value of this type instead?.

@objc func saveTapped(_ sender: UIBarButtonItem) {
        self.performSegue(withIdentifier: "saveTappedSegue", sender: self)
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "saveTappedSegue" {
            let dest = segue.destination as! MyViewControllerName
            
            let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
            let fileName = "Image.jpg"
            let fileURL = documentsDirectory.appendingPathComponent(fileName)
            if let data = self.jpegData(compressionQuality: 1.0), //Error here
                !FileManager.default.fileExists(atPath: fileURL.path) {
                do {
                    try data?.write(to: fileURL!)
                    print("Image Saved")
                } catch {
                    print("error saving file:", error)
                }
            }
        
// Remaining code includes writing strings to realm not yet linked to the image.Path. This will be attempted once I can solve this error.

        }
    }

UPDATE - added more code

 public var imagePickerController: UIImagePickerController?
    
    public var defaultImageUrl: URL?
       
       internal var selectedImage: UIImage? {
           get {
               return self.selectedImageView.image
           }
           
           set {
               switch newValue {
               case nil:
                   self.selectedImageView.image = nil
                   self.selectImageButton.isEnabled = true
                   self.selectImageButton.alpha = 1
                   
                   self.removeImageButton.isEnabled = false
                   self.removeImageButton.alpha = 0
               default:
                   self.selectedImageView.image = newValue
                   self.selectImageButton.isEnabled = false
                   self.selectImageButton.alpha = 0
                   
                   self.removeImageButton.isEnabled = true
                   self.removeImageButton.alpha = 1
               }
           }
       }

and

 //image input codes
    @IBOutlet weak var selectedImageContainer: UIView!
    @IBOutlet weak var selectedImageView: UIImageView!   
    @IBOutlet weak var selectImageButton: UIButton! {
        didSet {
            guard let button = self.selectImageButton else { return }
            button.isEnabled = true
            button.alpha = 1
        }
    }
    

    @IBOutlet weak var removeImageButton: UIButton! {
        didSet {
            guard let button = self.removeImageButton else { return }
            button.isEnabled = false
            button.alpha = 0
        }
    }

Relevant info in viewDidLoad

override func viewDidLoad() {
        self.selectedImageView.contentMode = .scaleAspectFit
        self.selectImageButton.isEnabled = self.selectedImage == nil
        self.selectImageButton.alpha = 1

to save the image

//MARK: - "Select to Add Photo"
    @IBAction func selectImageButton(_ sender: Any) {
    
    if self.imagePickerController != nil {
            self.imagePickerController?.delegate = nil
            self.imagePickerController = nil
        }
        self.imagePickerController = UIImagePickerController.init()
        
        let alert = UIAlertController.init(title: "Select Source Type", message: nil, preferredStyle: .actionSheet)
        
        if UIImagePickerController.isSourceTypeAvailable(.camera) {
            alert.addAction(UIAlertAction.init(title: "Camera", style: .default, handler: { (_) in
                self.presentImagePicker(controller: self.imagePickerController!, source: .camera)
            }))
        }
        
        if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) {
            alert.addAction(UIAlertAction.init(title: "Photo Library", style: .default, handler: { (_) in
                self.presentImagePicker(controller: self.imagePickerController!, source: .photoLibrary)
            }))
        }
 alert.addAction(UIAlertAction.init(title: "Cancel", style: .cancel))
        self.present(alert, animated: true)
    }
    
    internal func presentImagePicker(controller: UIImagePickerController , source: UIImagePickerController.SourceType) {
        controller.delegate = self
        controller.sourceType = source
        controller.allowsEditing = true
        self.present (controller, animated: true)
    }
    
    
    @IBAction func removeImageButtonAction(_ sender: UIButton) {
        self.selectedImage = nil
    }

in my extensions I have

extension AddNewMealVC: UIImagePickerControllerDelegate, UINavigationControllerDelegate {


    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
       
        if let image = info[.editedImage] as? UIImage {
            self.selectedImageView.image = image
        } else if let image = info[.originalImage] as? UIImage {
            self.selectedImageView.image = image
        }
           picker.dismiss(animated: true) {
            picker.delegate = nil
            self.imagePickerController = nil
        }
    }

    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
         picker.dismiss(animated: true) {
            picker.delegate = nil
            self.imagePickerController = nil
        }
    }
}

Solution

  • jpegData is a instance method of UIImage. Let use:

    selectedImageView.image?.jpegData()