IWannaLearn
IWannaLearn

Reputation: 55

Document Directory: delete file and rename remaining files in Swift 4.2

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

Upvotes: 0

Views: 1169

Answers (1)

robowen5mac
robowen5mac

Reputation: 886

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.

Upvotes: 0

Related Questions