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