It seems the documentDirectory in Xcode8/Swift3/iOS10, in a framework, on iOS seems unwritable.
API's used / tried:
FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
( The last one does not seem to be preferred in Swift, which I can understand )
Now, whenever I try to write files to the URL returned in this area I do not seem to be capable of doing so ( both Simulator, and device ). Downloading the container or inspecting it does not show the files either ( I tried several methods of writing ). Also trying to create a directory to write into seems to fail.
The weird thing is that there is no error returned from within API's used or the FileManager itself.
Is there some horrible point I'm missing? Is it a bug I should report? Currently I moved to creating a directory in Library/ instead, as that seems to work and shouldn't be as volatile as Library/Cache/.
Code used to write ( realm.io was used before I decided to do this ):
let URLs = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let data = Data.random(32) // Generates a 32 byte long random blob
try! data.write(to: URLs.last!) // Crashing here with a forced unwrap is fine
The path that you are writing to is invalid – you're passing in the directory path instead of the path to the file you want to create. You can craft a path like this:
let path = NSString(string: URLs.last!.path).appendingPathComponent("foo.txt")
Turns out you need to completely reset your Simulators and restart Xcode. Fun stuff.
Related
If I print the document directory when the simulator starts, I get this:
let simulatorPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
print(simulatorPath)
//prints -> /Users/name/Library/Developer/CoreSimulator/Devices/[device-id]/data/Containers/Data/Application/[application-id]/Documents
If I open this directory with Finder, there are a few other folders there: /Library, /SystemData, and /tmp. Specifically, /Library/Caches/[domain.app]/[several cache files].
However, in my app, I'm creating a sqlite database using the file manager. And if I do the following after creating the database:
var path = FileManager.default.currentDirectoryPath + "Library/Caches"
let enumerator = FileManager.default.enumerator(atPath: path)
while let obj = enumerator?.nextObject() as? String {
print(obj)
}
This is printed:
ColorSync
ColorSync/com.apple.colorsync.devices
Desktop Pictures
Desktop Pictures/78DJQ81B-3D2C-46C7-A268-3CE1903213FE
Desktop Pictures/78DJQ81B-3D2C-46C7-A268-3CE1903213FE/lockscreen.png
domain.app
domain.app/SQLite
com.apple.cloudkit
com.apple.cloudkit/com.apple.cloudkit.launchservices.hostnames.plist
com.apple.iconservices.store
app
app/SQLite
app/SQLite/cache.db
But the contents of the /Library/Caches/[domain.app] folders are different when printed with the enumerator, vs visited in Finder. Am I wrong in assuming that
NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
and
FileManager.default.currentDirectoryPath + "/Documents"
point to the same location?
After stumbling around Finder for a while, I discovered the SQLite db file I was creating was showing up in /Library/Caches, but in my hard drive's root directory. According to docs for FileManager.default.currentDirectoryPath:
When an app is launched, this property is initially set to the app’s current working directory. If the current working directory is not accessible for any reason, the value of this property is nil.
Given this, I figured when I printed that value, and / came out, it was relatively referring to the simulated app's current directory. If anyone knows why this is the case, comments welcome.
I am having problems trying to load a document into a WKWebView when the document has been added to the app using iTunes file sharing.
If I include the file inside the app I can load it fine.
I am using this code to get the load the file:
let documentsURL = try! FileManager().url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let fooURL = documentsURL.appendingPathComponent(docFileName)
let docURL = URL(fileURLWithPath: fooURL.path)
let req = URLRequest(url:docURL)
docView!.load(req)
docURL looks like this:
file:///var/mobile/Containers/Data/Application/432E716E-F70D-4985-814C-FFE7ECE53EF8/Documents/filename.pdf
I have tried to check the file exists using this code:
FileManager().fileExists(atPath: fooURL.path)
This returns true. I have also tried to copy the file from the documents folder into the app folder but this returns an error of file not found (again this is even after checking the file exists)
Should WKWebView be able to load from this location? Or have I missed something here?
Perhaps you are looking for loadFileURL(_:allowingReadAccessTo:)
Though I didn't see it explicitly stated in the docs, it wouldn't surprise me if the security policies of WKWebView are getting in your way, and the presence of this method alone seems to confirm that ;-)
Happy coding!
I have weird issue with core data and iOS9 (9.3). This call throws BAD_ACCESS on iOS9:
let documents = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
It works nice on iOS 10, but crashes on iOS 9.
I was digging more and found that even if I call this, app crashes:
print(FileManager.SearchPathDirectory.documentDirectory)
What am I missing? Some config somewhere? I tried it on completely new project and on both device/emulator. I temporarily solved it by bridging it from Objective-C, but that is not right solution.
Try this
let documents = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
So problem was here:
https://github.com/apple/swift/pull/5055
Waiting for new xcode.
I am making an iPhone app and in a previous question I was told that I needed a valid file path for archiverootobject and unarchiverootobject but I don't know how to make one. So what is a valid file path to save arrays of custom classes?
Follow up question: On the linked question I have set up my methods to use invalid saves but it still works would anyone know why?
You can save it to a subdirectory folder named with your bundleID inside the application support folder or you can also save it to the preferences folder located inside the library directory:
let preferencesDirectoryURL = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first!.appendingPathComponent("Preferences", isDirectory: true)
let fileURL = preferencesDirectoryURL.appendingPathComponent("fileName.plist")
print(fileURL.path) // "/var/folders/.../Library/Preferences/fileName.plist
So, using Swift 2.0, it looks like Apple are steering us towards using NSURL rather than NSString for paths.
I’m trying to ascertain whether a file exists in the user’s Documents directory in iOS, and I can’t quite piece it together.
If I use the following, Swift 2.0 complains that I shouldn’t use stringByAppendingPathComponent, and that I should use URLs.
let documents = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
let dbPath = documents.stringByAppendingPathComponent(“Whatever.sqlite”)
If I then get the URL, like so:
let documentsURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let fileURL = documentsURL.URLByAppendingPathComponent("Retrollect.sqlite”)
I then can’t call NSFileManager.defaultManager().fileExistsAtPath to ascertain whether the file exists.
Is there an equivalent of fileExistsAtPath() for an NSURL, to look inside the user’s Documents directory?
Never mind, one of those "five seconds later" answers.
I can use fileExistsAtPath(theURL.path) to do this. Checking that the path is non-nil first, of course!
Swift 4 version:
FileManager.default.fileExists(atPath: url.path)