2

I have a file named Data.plist in my main bundle (at the root of the app directory), and I am trying to copy this file to user document directory for read and write operations, however, I got the following error when trying to copy the file:

CFURLCopyResourcePropertyForKey failed because it was passed an URL which has no scheme

Error in copying Data.plist: Error Domain=NSCocoaErrorDomain Code=262 "The file couldn’t be opened because the specified URL type isn’t supported

Code:

let fileManager = FileManager.default

var docDirectory: String? {
        let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
        let docDir = paths.first
        return docDir
    }
    
var dataFilePath: String? {
        guard let docPath = self.docDirectory else { return nil }
        return docPath.appending("/Data.plist")
}


func copyFile() {
  guard let path = dataFilePath else {
            return
        }
        
        guard fileManager.fileExists(atPath: path) else {
//            NSLog("Creating Data.plist")
//            fileManager.createFile(atPath: path, contents: nil, attributes: nil) // create the file
//            NSLog("created Data.plist file successfully")
            
            if let bundlePath = Bundle.main.path(forResource: "Data", ofType: "plist") {
                do {
                    let fromURL = URL(string: bundlePath)! 
                    let toURL = URL(string: "file://\(path)")!
                    try fileManager.copyItem(at: fromURL, to: toURL)
                    NSLog("Copied Data.plist to Document directory")
                } catch let error {
                    NSLog("Error in copying Data.plist: \(error)") // see the above quoted error message from here
                }
            }
            
            return
        }

}
Community
  • 1
  • 1
TonyW
  • 18,375
  • 42
  • 110
  • 183

2 Answers2

10

File system URLs must be created with the fileURLWithPath initializer which adds the file:// scheme the error message complains about:

let fromURL = URL(fileURLWithPath: bundlePath)
let toURL = URL(fileURLWithPath: path)

Nevertheless there is a more convenient way to create fromURL:

if let fromURL = Bundle.main.url(forResource: "Data", withExtension: "plist") { ...

I recommend to use generally the URL related API, for example

var docDirectory: URL {
    return try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
}

var dataFileURL: URL {
    return docDirectory.appendingPathComponent("Data.plist")
}

The huge benefit is you get non-optional values and get rid of a couple of guards.

vadian
  • 274,689
  • 30
  • 353
  • 361
  • Thanks for the fast reply. I found using the string typed paths work nicely without the hassle of dealing with NSURL: `try fileManager.copyItem(at: bundlePath, to: path)` – TonyW Mar 13 '17 at 18:25
  • 1
    It's not a hassle to deal with `URL`, eventually it's much more convenient. – vadian Mar 13 '17 at 18:28
0

Check if file Data.plist IS EXIST in the XCODE project.

OrdoDei
  • 1,379
  • 2
  • 16
  • 9