0

This is the same problem that is addressed in this SO post: How to rename files in documents directory but it did not help me at all. It is the only other post I've come across that seems related to my issue.

I have a collection view where images are added via an imagePickerController within didFinishPickingMediaWithInfo. It loops through the document directory and gives the chosen image a name according to the next index number available. So images get named image1.jpg, image2.jpg, etc. When the images get loaded into the collectionView, I again loop through and show the images in index order. When it is time to remove an image, I can locate it in the document directory and remove it but then the index order is interrupted and I can no longer load the images. So, if I remove image3.png, the document directory contains image1.jpg, image2.jpg, image4.jpg, image5.jpg, etc.

My current code to try to rename or move images within the directory is still looping over the index numbers and naturally stops when it comes to an empty index (image3.jpg). How can I make image4.jpg move to where image3.jpg used to be (and move all other images that follow the index where an image was deleted)?

I can't quite wrap my head around the logic needed to rename the files. Let me know if you need more code. All suggestions are appreciated. This is what I have currently:

@objc func tapToDelete(recognizer: UITapGestureRecognizer)
{

    let pointInCollectionView = recognizer.location(in: collectionView)
    let indexPath = collectionView.indexPathForItem(at: pointInCollectionView)

    countIndex = (indexPath?.row)! + 1

    let filepath = getFolderAndFilePath() //this gets the folder and filepath of each image


    let alert = UIAlertController(title: "Delete This Image?", message: "Are you sure? This cannot be undone.", preferredStyle: .alert)
    alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
    alert.addAction(UIAlertAction(title: "Delete", style: .destructive, handler: { (action) in
        do
        {
            try self.fileManager.removeItem(at: filepath as URL)
            self.imageArray.remove(at: self.countIndex)


            self.folderPath = self.getFolderPath()
            if self.folderPath != nil
            {
                var j = 0
                var z = 0
                var finalArray = [String]()

                do
                {
                    let directoryContent = try FileManager.default.contentsOfDirectory(at: self.folderPath! as URL, includingPropertiesForKeys: nil, options: [])


                    for _ in directoryContent
                    {
                        z += 1
                        let fileString = String(format: "image%d.jpg", z)
                        let oldPath = self.folderPath?.appendingPathComponent(fileString)
                        print("filename oldPath : \(String(describing: oldPath))")

                        if self.fileManager.fileExists(atPath: (oldPath?.path)!)
                        {
                            j += 1
                            let newFileName = String(format: "image%d.jpg", j)


                            finalArray.append(newFileName)

                            let newPath = oldPath?.deletingLastPathComponent().appendingPathComponent(newFileName)
                            print("new filename: \(String(describing: newFileName))")

                            _ = try? self.fileManager.moveItem(atPath: (oldPath?.path)!, toPath: (newPath?.path)!)

                        }
                        else
                        {
                            print("no file here")
                            //this is called when we get to the image removed(image3.jpg)
                        }
                        self.collectionView.reloadData() //this reloads the collectionview and updates the count but still shows image3 instead of image4 even though image3 has been removed from the directory
                    }
                }
                catch
                {
                    print("Could not search for urls of files in documents directory: \(error)")
                }
            }
        }
        catch
        {
            print(error)

        }

    }))
    self.present(alert, animated: true)
}
IWannaLearn
  • 55
  • 1
  • 9
  • Yes, that is true. I know that isn’t the best way but this is my starting point. Not sure how to handle this situation. :( – IWannaLearn Jan 11 '19 at 18:00
  • I don't fully understand your requirements but from what I have gathered I would create a model for each row in the collection view and one of the fields would be the file name/path. then if it gets removed, delete the file, remove the model, reload collection view. easy. don't need to store images in any order – Scriptable Jan 11 '19 at 18:01
  • for the models, you would likely need to store them in some DB like core data or realm btw if they are to be persistent – Scriptable Jan 11 '19 at 18:02
  • That is an interesting concept I've not seen before. I could try that. – IWannaLearn Jan 11 '19 at 18:05

1 Answers1

0

This might need some tweaking, but what about the following approach (in pseudo code) after you delete the file.

let directoryContent = try FileManager.default.contentsOfDirectory(at:   self.folderPath! as URL, includingPropertiesForKeys: nil, options: [])
var index = 1
var newImageArray:[URL] = []
for fileURL in directoryContent
{
    let newFileName = String(format: "image%d.jpg", index)
    let newFilePathURL = makePathAsYouWere()
    _ = try? self.fileManager.moveItem(atPath: fileURL, toPath: newFilePathURL)
    index += 1
    newImageArray.append(newFilePathURL)
}

self.imageArray = newImageArray

collectionView.reload()

Essentially, once you remove the files you will have a set of files that you can iterate over. That list might need to be sorted to get them in the correct order, but once they are sorted (file1, file2, file4, file5). You should be able to rename each sequentially to get them back in numerical order with no gaps since the approach above does not care about the index of the old file.

For the image array, you should just be able to create a new one with the new file paths your are creating, replace the old array and then trigger a reload. With this, you also don't have to remove the delete item from the image array, it will be removed when you rebuild things.

Let me know if that is enough to get you started, otherwise, I can try to pull together a fully worked example.

robowen5mac
  • 866
  • 8
  • 17
  • Yes! this worked perfectly to rename my images. Thank you!! The only problem that remains is that the collection view initially shows the original image3 image after collectionView.relaodData but on leaving the view and coming back it shows the correct previously image4 image. How would I update the imageArray to show the correct image upon removal of that index? Not sure if I explained this clearly... – IWannaLearn Jan 11 '19 at 18:26
  • Does the image array store the path to the image? – robowen5mac Jan 11 '19 at 18:27
  • In viewDidLoad it reads the directory and appends the path to the imageArray – IWannaLearn Jan 11 '19 at 18:33
  • Perfect, you got it again! I had to adjust a little because after I read the path in viewDidLoad, it gets converted into an image ** let image = UIImage(contentsOfFile: (file?.path)!) **. (Forgot to mention that) Also converting it my delete method made it all work seamlessly. Thanks again! – IWannaLearn Jan 11 '19 at 18:57
  • Glad I could help. – robowen5mac Jan 11 '19 at 18:57