Search code examples
swiftuiimagensfilemanagerfile-manager

Deleting and Image and Re-Writing it back again produces errors


I am trying to build an app, where user works with images and creates structs which contain several images with corresponding values. when the user fills in all the information and presses save the struct is generated, and then image gets saved in FileManager.default and the rest of the information is saved in User Defaults:

guard let documentDirectoryPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
            return
        }

        let imageName = name+"_"+String(banknote.key)+".png"
        let imgPath = documentDirectoryPath.appendingPathComponent(imageName)

        do {
            try banknote.value.pngData()?.write(to: imgPath)
            self.imageLoc[banknote.key] = imageName

        } catch {
            print("its an error")
        }

And then I use a function that pull the images for each instance back to UIImages if needed like so:

func getImages() -> [Int:UIImage]{
    var unarchivedImages = [Int:UIImage]()

    if !self.images.isEmpty {
        let documentDirectoryPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!

        for imageLoc in images{
            let imageURL = documentDirectoryPath.appendingPathComponent(imageLoc.value)
            let image = UIImage(contentsOfFile: imageURL.path)
            unarchivedImages[imageLoc.key] = image
        }
    }

The problem however arises when the user wants to update the instance, say change some other variable within. My procedure there is to delete the images first like this:

let documentDirectoryPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
        for imageLoc in images{

            let imageURL = documentDirectoryPath.appendingPathComponent(imageLoc.value)

            if FileManager.default.fileExists(atPath: imageURL.path){
                try? FileManager.default.removeItem(atPath: imageURL.path)
            } else {
                print("failed")
            }

        }

And then create a new instance and save it again as in the first block of code. However, if I use the deleting procedure I showed above, saving the image no longer works and shows me an error:

CreateDataWithMappedFile:1429: 'open' failed '/var/mobile/Containers/Data/Application/83615D52-A4E7-4930-ABE3-B3702AC294F2/Documents/h_1.png' error = 2 (No such file or directory)

handle_write_error:103: stream error

handle_write_error:103: No IDATs written into file

Any ideas?


Solution

  • After hours of futile debugging I found the problem. The issue is that initializing and passing images around through UIImage(contentsOfFile: ...) and UIImage(named: ...) both keep reference to the file, instead of keeping the data, which is more important, because the reference eventually gets deleted, while it is data that it being passed around. Thus, the solution is to use:

    let imageData = try? Data(contentsOf: imageURL)
    let image = UIImage(data: imageData!)