I'm working on a program that uploads images to a CollectionView
by accessing the user's photo library. It's looking great so far, and the majority of it is running smoothly.
However, when I exit out of the app and refresh it, the once uploaded photos don't appear anymore.
I'm only a little familiar with Core Data
and I've been trying to work it in, but all of my sources aren't that helpful.
Here's my code so far:
import UIKit
import PhotosUI
import Photos
import CoreData
class ViewController: UIViewController, PHPickerViewControllerDelegate {
@IBOutlet var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// set up collection
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: 125, height: 125)
collectionView.collectionViewLayout = layout
layout.minimumInteritemSpacing = 10
layout.minimumLineSpacing = 10
}
// 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
}
// add to user's photo array
print(image)
imageArray.append(image)
}
}
group.notify(queue: .main) {
self.collectionView.reloadData()
}
}
}
// user images below
var imageArray = [UIImage]()
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
cell.imageView.image = 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)
}
}
I don't know where to start! Any ideas?
CodePudding user response:
For your question, reason your app lost all photos everytime you refresh because it was temporary store but not save somewhere else ( internet or on local).
If you want to save it on you own server, create server side and do with api.
Come to local here, you have come to the right path finding a local which is Core Data
to store. But the key point to need to know here is:
- Saving image to local should use FileManager ( which means each app have the own documentary folder in your phone so save the not only image but document, files, everything else to here - It will lost only when your app is uninstalled) You just need to keep the name of the image ( you can create your own name to save image)
Code will be like this
func saveImage(imageName: String, image: UIImage) {
// get documentary path to save image to
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
let fileName = imageName
let fileURL = documentsDirectory.appendingPathComponent(fileName)
guard let data = image.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)
}
}
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
}
Next is the Core Data
or UserDefaults
is where you save the key connect to the list of name images you save before. So everytime you come into app, just take the list image name out from the key and appear it again
I will do with UserDefaults
you can try to implement the same with CoreData
. I save image as name is number so I save to UserDefault
only the number of images. You can change to something like you want
Code will be like this
var imageArray = [UIImage]()
var countImage = 0
override func viewDidLoad() {
super.viewDidLoad()
// get number of image have been saved
let countImage = UserDefaults.standard.integer(forKey: "test")
if countImage < 1 {
return
}
for i in 1...countImage {
// get image from disk
imageArray.append(self.loadImageFromDiskWith(fileName: String(i))!)
}
print(imageArray)
self.collectionView.reloadData() // reload collection view
}
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
}
// add to user's photo array
print(image)
self.imageArray.append(image)
// append self.countImage to 1 and save number to UserDefault and image to FileManager
self.countImage = 1
UserDefaults.standard.set(self.countImage, forKey: "test")
self.saveImage(imageName: String(self.countImage), image: image)
}
}
group.notify(queue: .main) {
self.collectionView.reloadData()
}
}