Where is the Core Data file located? - ios

I use Core Data in my application, and I want to know that where is the SQLite file located.
I have already read the relative post and I didn't find the answer.

During initialization of the Core Data Stack you decide, where the database file will be located. The standard place is the documents directory. See Apple Developer - Initializing the Core Data Stack.
You will find there the following code
let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
let docURL = urls[urls.endIndex-1]
/* The directory the application uses to store the Core Data store file.
This code uses a file named "DataModel.sqlite" in the application's documents directory.
*/
let storeURL = docURL.URLByAppendingPathComponent("DataModel.sqlite")
The storeURL is the file URL you are looking for (and docURL is just a directory without a file name included).
You can also find this directory using NSSearchPathForDirectoriesInDomains
NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).last! as String
Check IOS 8 Store sqlite File Location Core Data for other ideas like find used in Terminal for example.

Related

What is correct way to store/retrieve user data (read/write files) in iPhone (iOS) dev via Swift?

Background
I've written one particular app via Windows Forms (C#), Android (Java and Kotlin), HTML5 Web App, ElectronJS (runs on Linux, Mac, and Win10) and even as a UWP (Universal Windows Platform) app.
All Use JSON File For Data
All of those apps use the exact same JSON formatted data for user settings.
That means I can share data on all platforms via the same file and file format.
On Android there is the additional benefit of having the file saved in the UserPrefs (which provides security and backup for user).
The Problem
I've also written the app as an iPhone/iPad app (Swift), however I cannot find the proper way to handle the JSON file storage.
The problem is not related to de-serializing the JSON into my business object. That all works fine. However, I am not sure about:
where should files be stored in the iPhone/iPad system?
can you save a file in some sort of user preference or appdata
location?
How do you open a file for read/write and read/write data? (Swift)
How can I better understand the paths available to read and write
files?
I've searched all over looking for this answer. Can you point me to official documentation, a book, a StackOverflow item or something that explains this clearly? (Hopefully with Swift examples.)
See iOS Storage Best Practices video and the File System Basics document. That should get you going.
In short, app data is generally stored in “application support directory”, documents exposed to the user (e.g. the Files app) are stored in “documents” folder, downloads that can be easily re-retrieved are stored in “caches” folder. Technically you could use UserDefaults for storing of this sort of application data, but it really is not intended for this purpose.
Re opening a file for “read/write”, when dealing with JSON, you don’t generally do that. You read the file into a Data and deserialize the JSON into your model objects.
do {
let fileURL = try FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent("appdata.json")
let data = try Data(contentsOf: fileURL)
let appData = try JSONDecoder().decode(AppData.self, from: data)
// do something with appData
} catch {
print(error)
}
When you want to update, you serialize the model objects into a Data containing your JSON and then write it to the file, replacing the file.
do {
let fileURL = try FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent("appdata.json")
let data = try JSONEncoder().encode(appData)
try data.write(to: fileURL)
} catch {
print(error)
}
Obviously, this assumes that the AppData type (or whatever you call it) conforms to Codable, but you said you were familiar with serialization of JSON. See Encoding and Decoding Custom Types for more information.

Why is there a mismatch between FileManager and Finder?

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.

Loading document in shared documents folder into WKWebView

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!

iOS10 + Xcode8 documentDirectory weird behavior

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.

Valid file path for archiverootobject and unarchiverootobject

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

Resources