How do I save images locally using NSUserData?

129 Views Asked by At

I'm working on a project where the user can upload images from their library into a gallery. It's working fine, but I want the images to stay even after I refresh the app. I've been told that NSUserData will actually work better than CoreData, but I'm having a LOT of trouble implementing it into my code. I've never worked with UserData, so I am completely lost. Any help would be appreciated!

View Controller:

//  ViewController.swift


import UIKit
import PhotosUI
import Photos
import CoreData
import Foundation


// user images below
var imageArray = [UIImage]()
var imageIDs = [""]
var countImage = 0


class ViewController: UIViewController, PHPickerViewControllerDelegate {

    
    let userDefaults = UserDefaults.standard
    
    
    @IBOutlet var collectionView: UICollectionView!
    
    // private let myFileManager = LocalFileManager.instance
    // private let folderName = "closet_folder"
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        
        // set up collection in closet
        navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addPhotos))
        
        
        collectionView.register(ClosetCollectionViewCell.nib(), forCellWithReuseIdentifier: "ClosetCollectionViewCell")
        
        collectionView.delegate = self
        collectionView.dataSource = self
        
        let layout = UICollectionViewFlowLayout()
        layout.itemSize = CGSize(width: 115, height: 115)
        collectionView.collectionViewLayout = layout
        
        layout.minimumInteritemSpacing = 6
        layout.minimumLineSpacing = 7
            
    }


    
    // access photo library
    @objc private func addPhotos() {
        var config = PHPickerConfiguration()
        config.selectionLimit = 10
        config.filter = .images
        let vc = PHPickerViewController(configuration: config)
        vc.delegate = self
        present(vc, animated: true)
    }
    
    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        picker.dismiss(animated: true, completion: nil)
        let group = DispatchGroup()
        
        results.forEach { result in
            group.enter()
            result.itemProvider.loadObject(ofClass: UIImage.self) { reading, error in
                defer {
                    group.leave()
                }
                guard let image = reading as? UIImage, error == nil else {
                    return
                }
                print(image)
                imageArray.append(image)
                
                // imageIDs.append("\(image)")
                countImage += 1
                print(countImage)
                imageIDs.append(String(countImage))
                // imageIDs.append("\(image)")
                LocalFileManager.instance.saveImage(image: image, imageName: String(countImage), folderName: "closet_folder")
            
            }
        }
        
        group.notify(queue: .main) {
            self.collectionView.reloadData()
        }
        
        
    }
    
}


extension ViewController: UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        collectionView.deselectItem(at: indexPath, animated: true)
        print("you tapped me!")
        // when cell is tapped...
    }
}

extension ViewController: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        // how many cells are shown? based on number of items the user uploaded
        return imageArray.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        // return cell for given item
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ClosetCollectionViewCell", for: indexPath) as! ClosetCollectionViewCell
        // show every cell in imageArray
        cell.imageView.image = LocalFileManager.instance.getImage(imageName: imageIDs[indexPath.row + 1], folderName: "closet_folder")
        //imageArray[indexPath.row]
        
        return cell
    }
}

extension ViewController: UICollectionViewDelegateFlowLayout {
    // margin of padding between cells
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: 115, height: 115)
    }
    
}

Here's the code with the saveImage and getImage functions: It generates URLs for every image and the folder it's stored in.

//
//  LocalFileManager.swift

import Foundation
import SwiftUI

class LocalFileManager {
    static let instance = LocalFileManager()
    private init() {}
    
    
    
    func saveImage(image: UIImage, imageName: String, folderName: String) {
        // create folder
        createFolderIfNeeded(folderName: folderName)
        
        // get path for image
        guard
            let data = image.pngData(),
            let url = getURLforImage(imageName: imageName, folderName: folderName)
        else { return  }
        
        // save image to path
        do {
            try data.write(to: url)
        } catch let error {
            print("image name: \(image) error saving image: \(error)")
        }
        
    }
    
    
    func getImage(imageName: String, folderName: String) -> UIImage? {
        guard let url = getURLforImage(imageName: imageName, folderName: folderName),
              FileManager.default.fileExists(atPath: url.path)
        else {
            return nil
        }
        return UIImage(contentsOfFile: url.path)
    }
    
    
    
    // referenced functions below
    
    // create folder to store images
    private func createFolderIfNeeded(folderName: String) {
        guard let url = getURLforFolder(folderName: folderName) else {
            return
        }
        if !FileManager.default.fileExists(atPath: url.path) {
            do {
                try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true)
            }
            catch let error {
                print("folder name: \(folderName) error creating folder! \(error)")
            }
        }
    }
    
    // get URL for that folder
    private func getURLforFolder(folderName: String) -> URL? {
        guard let url = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first
        else {
            return nil
        }
        return url.appendingPathExtension(folderName)
    }
    
    // generate URL for images in folder
    private func getURLforImage(imageName: String, folderName: String) -> URL? {
        guard let folderURL = getURLforFolder(folderName: folderName) else {
            return nil
        }
        return folderURL.appendingPathExtension(imageName)
    }
    
}

0

There are 0 best solutions below