3

Trying to archive an array of Codable elements.

do {
   let data = try PropertyListEncoder().encode(elements)
   let success = NSKeyedArchiver.archiveRootObject(data, toFile:self.archiveURL.path)
   print(success ? "Successful save" : "Save Failed")
} catch {
   print("Save Failed")
}

For some reason path (archiveURL) is constantly wrong:

let archiveURL = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first!

is returning always URL like this:

file:///Users/userName/Library/Developer/CoreSimulator/Devices/deviceID/data/Documents

but searching through folders I see no /Documents folder. Has something changed recently? It used to work few weeks back (pretty sure). Super annoying and I can't find any workaround/fix for that.

raistlin
  • 4,298
  • 5
  • 32
  • 46

3 Answers3

3

I believe this is a (new-ish) "feature" of the iOS simulators - not all of the ususal directories exist when an app is initially installed.

Fortunately it's easy to create them, e.g. for the applicationSupport directory I do this in my apps:

let fileManager = FileManager.default
let directory = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).first!
if !fileManager.fileExists(atPath: directory) {
  try fileManager.createDirectory(atPath: directory, withIntermediateDirectories: true, attributes: nil)
}
Gereon
  • 17,258
  • 4
  • 42
  • 73
  • 1
    `Documents` **does** exist, the framework creates the directory implicitly. And `NSSearchPathForDirectoriesInDomains` is outdated, use `let directory = try FileManager.default.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)`. It creates the directory if it doesn't exist. – vadian May 02 '18 at 11:34
  • @vadian thing is that this directory did not exist, but I ended up with creating directory your way :) – raistlin May 02 '18 at 13:15
  • I've also had this problem, it created some quite annoying errors on my CI server. Do you know if it is documented by Apple that these directories are not guaranteed to exist? – Jan Nash Sep 27 '18 at 11:32
3

This happens in Simulators running iOS 11.x and up.

Before iOS 11, the Simulator created the global (app independent) Documents folder on startup. Since iOS 11.x (don't know if it was a special point release), this does not happen anymore.

Be aware that NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first returns this global documents path only in (unit) tests, not when running the app. If you run the app, you get the application specific Documents folder which is still created when installing the app in the simulator.

This seems to be a bug on Apple side. If you run into this issue (as it seems you have), please file a bug report at https://developer.apple.com/bug-reporting/.

ChaosCoder
  • 3,085
  • 1
  • 22
  • 23
1

You cannot (over)write the Documents directory, you have to append a file name.

And why do you archive the data? You can write the property list data directly to disk.

And never ever print a meaningless literal string in the catch clause, print at least the actual error.

let fileName = "myPropertyList.plist"
let fileURL = archiveURL.appendingPathComponent(fileName)
do {
   let data = try PropertyListEncoder().encode(elements)
   try data.write(to: fileURL)
} catch {
   print("Save Failed", error)
}
vadian
  • 274,689
  • 30
  • 353
  • 361
  • thanks for quick response and tips though 1) I don't want to actually overwrite `Documents`, especially **it is not existing** so I guess still (appended with filename) the URL will be useless, as `write` does not create file – raistlin May 02 '18 at 12:19
  • Try it out! It's supposed to work. `write` **does** create file. – vadian May 02 '18 at 12:21