Search code examples
iosxcodeios11xcode9-beta

iOS NSData.write(toFile) returns false when writing zip to cacheDirectory


I'm trying to download a zip file, and write it to the cacheDirectory before extracting it. However, write(toFile:) always returns false:

import Foundation

func downloadFile(url: URL, completion: @escaping (Result<Data>) -> Void) {
    print("starting dqueue to download " + url.absoluteString)
    DispatchQueue.global(qos: .background).async {
        print("Starting download")
        let data = NSData.init(contentsOf: url)
        if data == nil {
            print("Data nil!")
        }

        // Find cache
        print("Got data!")
        let paths = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true)
        let path = paths[0]

        let dataPath = URL(fileURLWithPath: path).appendingPathComponent("mod.zip")
        if (FileManager.default.fileExists(atPath: dataPath.absoluteString)) {
            print("File already exists!")
        }

        // Save data
        print("Saving to " + dataPath.absoluteString)
        if (data?.write(toFile: dataPath.absoluteString, atomically: true) ?? false) {
            if (FileManager.default.fileExists(atPath: dataPath.absoluteString)) {
                print("exists!")
            } else {
                print("does not exist!")
            }

            if (FileManager.default.isWritableFile(atPath: dataPath.absoluteString)) {
                print("Writable")
            }else {
                print("Not Writable")
            }

            DispatchQueue.main.async {
                print("This is run on the main queue, after the previous code in outer block")
            }
        } else {
            print("Failed to write to file!")
        }
    }
}

Here is the log output:

starting dqueue to download https://github.com/minetest-mods/armor_monoid/archive/c7988a3dae32f2c1cb93fde31d9e53222a205eea.zip
Starting download
Got data!
Saving to file:///var/mobile/Containers/Data/Application/E734C574-1E94-44CB-9A6E-2AE1C8850E88/Library/Caches/mod.zip
Failed to write to file!

I've tried:

I'm using Xcode v9.0 beta 2 (9M137d) with an IPad Air 2 (iOS 11.0 15A5318g)


Solution

  • You need to use relativePath rather than absoluteString.

    Try this (I tried, it worked):

    import Foundation
    
    func downloadFile(url: URL, completion: @escaping (Result<Data>) -> Void) {
        print("starting dqueue to download " + url.absoluteString)
        DispatchQueue.global(qos: .background).async {
            print("Starting download")
            let data = NSData.init(contentsOf: url)
            if data == nil {
                print("Data nil!")
            }
    
            // Find cache
            print("Got data!")
            let paths = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true)
            let path = paths[0]
    
            let dataPath = URL(fileURLWithPath: path).appendingPathComponent("mod.zip")
            if (FileManager.default.fileExists(atPath: dataPath.relativePath)) {
                print("File already exists!")
            }
    
            // Save data
            print("Saving to " + dataPath.relativePath)
            if (data?.write(toFile: dataPath.relativePath, atomically: true) ?? false) {
                if (FileManager.default.fileExists(atPath: dataPath.relativePath)) {
                    print("exists!")
                } else {
                    print("does not exist!")
                }
    
                if (FileManager.default.isWritableFile(atPath: dataPath.relativePath)) {
                    print("Writable")
                }else {
                    print("Not Writable")
                }
    
                DispatchQueue.main.async {
                    print("This is run on the main queue, after the previous code in outer block")
                }
            } else {
                print("Failed to write to file!")
            }
        }
    }