What’s new in Core Data Swift 3.0 – JaywayJayway
original source : https://blog.jayway.com/2016/08/12/whats-new-core-data-swift-3-0/
Apple has made some big changes in Core Data and taken the burdens from our shoulders.In this blog post we will be comparing Core Data with Xcode 7.3.1 vs new Core Data with Xcode 8 beta to see if it has become any easier to use Core Data.If we are creating a new application with Single View Application or Master-Detail Application we can check the Use Core Data option and Xcode will automatically generate some boilerplate code in AppDelegate class. But what if you’re creating a Tabbed Application, Page- Based Application, Game, or even planning to add Core Data to an existing project? We can create a new Single View Application or Master-Detail Application and then copy all the code for core data from AppDelegate and paste it in our current project’s AppDelegate class. In both cases the AppDelegate class will be full with boilerplate code which are quite some lines of code.An even better solution is to create a new class for the Core Data and put all the boilerplate code there. Then modify it as you wish, and you can use that class in all of your projects. Having a separate class will make your life easier in case you want to perform any kind of Migration in future releases of your app. Or even if you have an extension where both your container app and extension can access this class.Here I Have created a class called CoreDataStack.swift and moved all the Core Data code from AppDelegate to CoreDataStack.swift
import CoreData
class CoreDataStack {
// Applications default directory address
lazy var applicationDocumentsDirectory: NSURL = {
let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
return urls[urls.count-1]
}()
lazy var managedObjectModel: NSManagedObjectModel = {
// 1
let modelURL = NSBundle.mainBundle().URLForResource(“Supercars”, withExtension: “momd”)!
return NSManagedObjectModel(contentsOfURL: modelURL)!
}()
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent(“SuperCars.sqlite”)
do {
// If your looking for any kind of migration then here is the time to pass it to the options
try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil)
} catch let error as NSError {
print(“Ops there was an error (error.localizedDescription)”)
abort()
}
return coordinator
}()lazy var managedObjectContext: NSManagedObjectContext = {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the
application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to
fail.
let coordinator = self.persistentStoreCoordinator
var context = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
context.persistentStoreCoordinator = coordinator
return context
}()
// if there is any change in the context save it
func saveContext() {
if mangagedObjectContext.hasChanges {
do {
try managedObjectContext.save()
} catch let error as NSError {
print(“Ops there was an error (error.localizedDescription)”)
abort()
}
}
}
}
1. For Managed Object Model name Apple uses your application name by default but you can name it anything you like.
Keep in mind that you have to name your Data Model the same as your Managed Object Model for this example the name should be (Supercars.xcdatamodeld)
Ok now let’s see how do we use this class in AppDelegate.swift First we have to import core data.
import CoreData
Inside AppDelegate class we create a new lazy var instance of this class
lazy var coreDataStack = CoreDataStack()
However this blog post is not about Swift properties but you might be wondering why lazy var. we have seen lazy property in front of var many times now. Can we not just write the same line of code without lazy property like this
var coreDataStack = CoreDataStack()
Actually we can, but lets see what Apple says about it and why it’s good to use it in this case.
A lazy stored property is a property whose value is not calculated until the first time it is used.
Ok enough talked about lazy property. Now let’s see how we can call save function in applicationWillTerminate function in AppDelegate class.
func applicationWillTerminate(application: UIApplication) {
coreDataStack.saveContext()
}
Now if we look at our AppDelegate class it’s a lot more clean and we can use CoreDataStack class in as many projects as we like.
But wait This post is not about refactoring we want to see what’s new in Core Data
I can say that Apple is try to tie our hands up and don’t want us to type a lot. Here is the same CoreDataStack class created in Xcode 8 beta and Swift 3 I think even a none programmer can see the big difference by counting lines of code in both classes.
import CoreData
class CoreDataStack {
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: “Supercars”)
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error {
fatalError(“Unresolved error (error), (error.userInfo)”)
}
})
return container
}()func saveContext() {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch let error as NSError {
fatalError(“Unresolved error (error), (error.userInfo)”)
}
}
}
}
Yes this is all the code in our new CoreDataStack class. You Create a persistentContainer it takes care of creating and loading your Managed Object Model. Everything is now encapsulated inside a single NSPersistentContainer class.
You may ask for few lines of code why I have created a class you can leave it in your AppDelegate class it’s totally fine. I think having it in a separate class will help you in the future for example if you want to make changes in your Data Model then you have to deal with Migration. Also your AppDelegate will be a few lines less and clean.
So is it all the changes in this new update for Core Data? The answer is NO.
let’s see how can we get an entity and add an item to it in current version of Core Data and Xcode 7.3 of course Swift 2.2
let entity = NSEntityDescription.entityForName(“Car”, inManagedObjectContext: context)
let car = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: context)
car.setValue(“Ferrari”, forKey: “name”)
We can generate NSManagedObject subclass for our entity in that case the code will be like this
let entity = NSEntityDescription.entityForName(“Car”, inManagedObjectContext: context)
let car = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: context) as! Car
car.name = “Ferrari"
Generating NSManagedObject subclass for Entity is useful thing to do. It helps you eliminate key-value coding which can lead to any kind of mistyping, misspelling also gives you ability to use dot notation and so on. But you have to know that everything comes with a price. You have to generate NSManagedObject classes manually for your entities. Xcode will add 2 new files to your source tree per entity. Think if you have 5 entities then Xcode will add 10 new .swift files to your source tree not only that every time you make a change to any of your entity you have to regenerate your NSManagedObject subclass for that entity.
Now let’s see how can we get the entity and add an item to it in Xcode 8 and swift 3
let car = Car(context: context)
car.name = “Ferrari”
That’s it. No more key-value coding, No more type casting, You don’t have to generate NSManagedObject subclasses yourself as soon as you add an entity to your Data Model build your project and Xcode 8 will happily take care of all those subclasses for you. Oh and your source tree will be clean as well.
I tried to quickly point a few important changes but there are a lot which has been changed. If you’re interested to know more watch WWDC 2016 What’s new in Core Data video.
Core Data Basics: Preload Data and Use Existing SQLite Database
original source : https://www.appcoda.com/core-data-preload-sqlite-database/
Editor’s note: This is a sample chapter of our new book, Intermediate iOS 8 Programming with Swift.
When working with Core Data, you may have asked these two questions:
- How can you preload existing data into the SQLite database?
- How can you use an existing SQLite database in my Xcode project?
I recently met a friend who is now working on a dictionary app for a particular industry. He got the same questions. He knows how to save data into the database and retrieve them back from the Core Data store. The real question is: how could he preload the existing dictionary data into the database?
I believe some of you may have the same question. This is why I devote this tutorial to talk about data preloading in Core Data. I will answer the above questions and show you how to preload your app with existing data.
So how can you preload existing data into the built-in SQLite database of your app? In general you bundle a data file (in CSV or JSON format or whatever format you like). When the user launches the app for the very first time, it preloads the data from the data file and puts them into the database. At the time when the app is fully launched, it will be able to use the database, which has been pre-filled with data. The data file can be either bundled in the app or hosted on a cloud server. By storing the file in the cloud or other external sources, this would allow you to update the data easily, without rebuilding the app. I will walk you through both approaches by building a simple demo app.
Once you understand how data preloading works, I will show you how to use an existing SQLite database (again pre-filled with data) in your app.
Note that I assume you have a basic understanding of Core Data. You should know how to insert and retrieve data through Core Data. If you have no ideas about these operations, you can refer to our book, Beginning iOS 8 Programming with Swift or refer to this tutorial (in Objective-C).
A Simple Demo App
To keep your focus on learning data preloading, I have created the project template for you. Firstly, download the project and have a trial run.
It’s a very simple app showing a list of food. By default, the starter project comes with an empty database. When you compile and launch the app, your app will end up a blank table view. What we are going to do is to preload the database with existing data.

I have already built the data model and provided the implementation of the table view. You can look into the MenuItemTableViewController class and CoreDataDemo.xcdatamodeld for details. The data model is pretty simple. I have defined a MenuItem entity, which includes three attributes: name, detail, and price.
Once you’re able to preload the database with the food menu items, the app will display them accordingly, with the resulting user interface similar to the screenshot shown on the left.
The CSV File
In this demo I use a CSV file to store the existing data. CSV files are often used to store tabular data and can be easily created using text editor, Numbers or MS Excel. They are sometimes known as comma delimited files. Each record is one line and fields are separated with commas. In the project template, you should find the “menudata.csv” file. It contains all the food items for the demo app in CSV format. Here is a part of the file
The first field represents the name of the food menu item. The next field is the detail of the food, while the last field is the price. Each food item is one line, separated with a new line separator.


Parsing CSV Files
It’s not required to use CSV files to store your data. JSON and XML are two common formats for data interchange and flat file storage. As compared to CSV format, they are more readable and suitable for storing structured data. Anyway, CSV has been around for a long time and is supported by most spreadsheet applications. At some point of time, you will have to deal with this type of file. So I pick it as an example. Let’s see how we can parse the data from CSV.
The AppDelegate object is normally used to perform tasks during application startup (and shutdown). To preload data during the app launch, we will add a few methods in the AppDelegate class. First, insert the following method for parsing the CSV file:
func parseCSV (contentsOfURL: NSURL, encoding: NSStringEncoding, error: NSErrorPointer) -> [(name:String, detail:String, price: String)]? {
// Load the CSV file and parse it
let delimiter = “,”
var items:[(name:String, detail:String, price: String)]?
if let content = String(contentsOfURL: contentsOfURL, encoding: encoding, error: error) {
items = []
let lines:[String] = content.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet()) as [String]
for line in lines {
var values:[String] = []
if line != “” {
// For a line with double quotes
// we use NSScanner to perform the parsing
if line.rangeOfString(“””) != nil {
var textToScan:String = line
var value:NSString?
var textScanner:NSScanner = NSScanner(string: textToScan)
while textScanner.string != “” {
if (textScanner.string as NSString).substringToIndex(1) == “”” {
textScanner.scanLocation += 1
textScanner.scanUpToString(“””, intoString: &value)
textScanner.scanLocation += 1
} else {
textScanner.scanUpToString(delimiter, intoString: &value)
}
// Store the value into the values array
values.append(value as! String)
// Retrieve the unscanned remainder of the string
if textScanner.scanLocation < count(textScanner.string) {
textToScan = (textScanner.string as NSString).substringFromIndex(textScanner.scanLocation + 1)
} else {
textToScan = “”
}
textScanner = NSScanner(string: textToScan)
}
// For a line without double quotes, we can simply separate the string
// by using the delimiter (e.g. comma)
} else {
values = line.componentsSeparatedByString(delimiter)
}
// Put the values into the tuple and add it to the items array
let item = (name: values[0], detail: values[1], price: values[2])
items?.append(item)
}
}
}
return items
}
The method takes in three parameters: the file’s URL, encoding and an error pointer. It first loads the file content into memory, reads the lines into an array and then performs the parsing line by line. At the end of the method, it returns an array of food menu items in the form of tuples.
A simple CSV file only uses a comma to separate values. Parsing such kind of CSV files shouldn’t be difficult. You can call the componentsSeparatedByString method (highlighted in yellow in the code snippet) to split a comma-delimited string. It’ll then return you an array of strings that have been divided by the separator.
For some CSV files, they are more complicated. Field values containing reserved characters (e.g. comma) are surrounded by double quotes. Here is another example:
Country Breakfast,“Two eggs as you like, Batter Home Fries, country slab bacon, sausage, scrapple or ham steak and toast”, 8.5
In this case, we cannot simply use the componentsSeparatedByString method to separate the field values. Instead, we use NSScanner to go through each character of the string and retrieve the field values. If the field value begins with a double quote, we scan through the string until we find the next double quote character by calling the scanUpToString method. The method is smart enough to extract the value surrounded by the double quotes. Once a field value is retrieved, we then repeat the same procedure for the remainder of the string.
After all the field values are retrieved, we save them into a tuple and then put it into the “items” array.
Preloading the Data and Saving it into database
Now that you’ve created the method for CSV parsing, we now move onto the implementation of data preloading. The preloading will work like this:
- First, we will remove all the existing data from the database. This operation is optional if you can ensure the database is empty.
- Next, we will call up the parseCSV method to parse menudata.csv.
- Once the parsing completes, we insert the food menu items into the database.
Add the following code snippets into the AppDelegate.swift file:
func preloadData () {
// Retrieve data from the source file
if let contentsOfURL = NSBundle.mainBundle().URLForResource(“menudata”, withExtension: “csv”) {
// Remove all the menu items before preloading
removeData()
var error:NSError?
if let items = parseCSV(contentsOfURL, encoding: NSUTF8StringEncoding, error: &error) {
// Preload the menu items
if let managedObjectContext = self.managedObjectContext {
for item in items {
let menuItem = NSEntityDescription.insertNewObjectForEntityForName(“MenuItem”, inManagedObjectContext: managedObjectContext) as! MenuItem
menuItem.name = item.name
menuItem.detail = item.detail
menuItem.price = (item.price as NSString).doubleValue
if managedObjectContext.save(&error) != true {
println(“insert error: (error!.localizedDescription)”)
}
}
}
}
}
}
func removeData () {
// Remove the existing items
if let managedObjectContext = self.managedObjectContext {
let fetchRequest = NSFetchRequest(entityName: “MenuItem”)
var e: NSError?
let menuItems = managedObjectContext.executeFetchRequest(fetchRequest, error: &e) as! [MenuItem]
if e != nil {
println(“Failed to retrieve record: (e!.localizedDescription)”)
} else {
for menuItem in menuItems {
managedObjectContext.deleteObject(menuItem)
}
}
}
}
The removeData method is used to remove any existing menu items from the database. I want to ensure the database is empty before populating the data extracted from the menudata.csv file. The implementation of the method is very straightforward if you have a basic understanding of Core Data. We first execute a query to retrieve all the menu items from the database and call the deleteObject method to delete the item one by one.
Okay, now let’s talk about the preloadData method.
In the method we first retrieve the file URL of the menudata.csv file using this line of code:
NSBundle.mainBundle().URLForResource(“menudata”, withExtension: “csv”)
After calling the removeData method, we execute the parseCSV method to parse the menudata.csv file. With the returned items, we insert them one by one by calling the NSEntityDescription.insertNewObjectForEntityForName method.
Lastly, execute the preloadData() method in the didFinishLaunchingWithOptions method:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
preloadData()
return true
}
Now you’re ready to test your app. Hit the Run button to launch the app. If you’ve followed the implementation correctly, the app should be preloaded with the food items.
But there is an issue with the current implementation. Every time you launch the app, it preloads the data from the CSV file. Apparently, you only want to perform the preloading once. Change the application:didFinishLaunchingWithOptions: method to the following:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let defaults = NSUserDefaults.standardUserDefaults()
let isPreloaded = defaults.boolForKey(“isPreloaded”)
if !isPreloaded {
preloadData()
defaults.setBool(true, forKey: “isPreloaded”)
}
return true
}
To indicate that the app has preloaded the data, we save a setting to the defaults system using a specific key (i.e. isPreloaded). Every time when the app is launched, we will first check if the value of the “isPreloaded” key. If it’s set to true, we will skip the data preloading operation.
Using External Data Files
So far the CSV file is bundled in the app. If your data is static, it is completely fine. But what if you’re going to change the data frequently? In this case, whenever there is a new update for the data file, you will have to rebuild the app and redeploy it to the app store.
There is a better way to handle this.
Instead of embedding the data file in the app, you put it in an external source. For example, you can store it on a cloud server. Every time when a user opens the app, it goes up to the server and download the data file. Then the app parses the file and loads the data into the database as usual.
I have uploaded the sample data file to the Amazon cloud server. You can access it through the URL below:
This is just for demo purpose. If you have your own server, feel free to upload the file to the server and use your own URL. To load the data file from the remote server, all you need to do is make a little tweak to the code. First, update the preloadData method to the following:
func preloadData () {
// Remove all the menu items before preloading
removeData()
var error:NSError?
let remoteURL = NSURL(string: “https://s3.amazonaws.com/swiftbook/menudata.csv”)!
if let items = parseCSV(remoteURL, encoding: NSUTF8StringEncoding, error: &error) {
// Preload the menu items
if let managedObjectContext = self.managedObjectContext {
for item in items {
let menuItem = NSEntityDescription.insertNewObjectForEntityForName(“MenuItem”, inManagedObjectContext: managedObjectContext) as! MenuItem
menuItem.name = item.name
menuItem.detail = item.detail
menuItem.price = (item.price as NSString).doubleValue
if managedObjectContext.save(&error) != true {
println(“insert error: (error!.localizedDescription)”)
}
}
}
}
}
The code is very similar to the original one. Instead loading the data file from the bundle, we specify the remote URL and pass it to the parseCSV method. That’s it. The parseCSV method will handle the file download and perform the data parsing accordingly.
Before running the app, you have to update the application:didFinishLaunchingWithOptions: method so that the app will load the data every time it runs:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
preloadData()
return true
}
You’re ready to go. Hit the Run button and test the app again. The menu items should be different from those shown previously.
For your reference, you can download the complete Xcode project here.
Using An Existing Database in Your Project
Now that you should know how to populate a database with external data, you may wonder if you can use an existing SQLite database directly. In some situations, you probably do not want to preload the data during app launch. For example, you need to preload hundreds of thousands of records. This will take some time to load the data and results a poor user experience.
Apparently, you want to pre-filled the database beforehand and bundle it directly in the app.
Suppose you’ve already pre-filled an existing database with data, how can you bundle it in your app?
Before I show you the procedures, please download the starter project again. As a demo, we will copy the existing database created in the previous section to this starter project.
Now open up the Xcode project that you have worked on earlier. If you’ve followed me along, your database should be pre-filled with data. We will now copy it to the starter project that you have just downloaded.
But where is the SQLite database?
The database is not bundled in the Xcode project but automatically created when you run the app in the simulator. To locate the database, you will need to add a line of code to reveal the file path. Update the application:didFinishLaunchingWithOptions: method to the following:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
println(applicationDocumentsDirectory.path)
preloadData()
return true
}
The SQLite database is generated under the application’s document directory. To find the file path, we simply print out the value of applicationDocumentsDirectory.path variable.
Now run the app again. You should see an output in the console window showing the full path of the document directory.


Copy the file path and go to Finder. In the menu select Go > Go to Folder… and then paste the path in the pop-up. Click “Go” to confirm.


Once you open the document folder in Finder, you will find three files: CoreDataDemo.sqlite, CoreDataDemo.sqlite-wal and CoreDataDemo.sqlite-shm.

Starting from iOS 7, the default journaling mode for Core Data SQLite stores is set to Write-Ahead Logging (WAL). With the WAL mode, Core Data keeps the main .sqlite file untouched and appends transactions to a .sqlite-wal file in the same folder. When running WAL mode, SQLite will also create a shared memory file with .sqlite-shm extension. In order to backup the database or use it to in other projects, you will need copy these three files. If you just copy the CoreDataDemo.sqlite file, you will probably end up with an empty database.
Now, drag these three files to the starter project in Xcode.


When prompted, please ensure the “Copy item if needed” option is checked and the “CoreDataPreloadDemo” option of “Add to Targets” is selected. Then click “Finish” to confirm.


Now that you’ve bundled an existing database in your Xcode project. When you build the app, this database will be embedded in the app. But you will have to tweak the code a bit before the app is able to use the database.
By default, the app will create an empty SQLite store if there is no database found in the document directory. So all you need to do is copy the database files bundled in the app to that directory. In the AppDelegate class update the declaration of the persistentStoreCoordinator variable like this:
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = {
// The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
// Create the coordinator and store
var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent(“CoreDataDemo.sqlite”)
if !NSFileManager.defaultManager().fileExistsAtPath(url.path!) {
let sourceSqliteURLs = [NSBundle.mainBundle().URLForResource(“CoreDataDemo”, withExtension: “sqlite”)!, NSBundle.mainBundle().URLForResource(“CoreDataDemo”, withExtension: “sqlite-wal”)!, NSBundle.mainBundle().URLForResource(“CoreDataDemo”, withExtension: “sqlite-shm”)!]
let destSqliteURLs = [self.applicationDocumentsDirectory.URLByAppendingPathComponent(“CoreDataDemo.sqlite”),
self.applicationDocumentsDirectory.URLByAppendingPathComponent(“CoreDataDemo.sqlite-wal”),
self.applicationDocumentsDirectory.URLByAppendingPathComponent(“CoreDataDemo.sqlite-shm”)]
var error:NSError? = nil
for var index = 0; index < sourceSqliteURLs.count; index++ {
NSFileManager.defaultManager().copyItemAtURL(sourceSqliteURLs[index], toURL: destSqliteURLs[index], error: &error)
}
}
var error: NSError? = nil
var failureReason = “There was an error creating or loading the application’s saved data.”
if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil, error: &error) == nil {
coordinator = nil
// Report any error we got.
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = “Failed to initialize the application’s saved data”
dict[NSLocalizedFailureReasonErrorKey] = failureReason
dict[NSUnderlyingErrorKey] = error
error = NSError(domain: “YOUR_ERROR_DOMAIN”, code: 9999, userInfo: dict)
// Replace this with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(“Unresolved error (error), (error!.userInfo)”)
abort()
}
return coordinator
}()
The changes are highlighted in yellow. We first verify if the database exists in the document folder. If not, we copy the SQLite files from the bundle folder to the document folder by calling the copyItemAtURL method of NSFileManager.
That’s it! Before you hit the Run button to test the app, you better delete the CoreDataPreloadDemo app from the simulator or simply reset it (select iOS Simulator > Reset Content and Settings). This is to remove any existing SQLite databases from the simulator.
Okay, now you’re good to go. When the app is launched, it should be able to use the database bundled in the Xcode project.
For reference, you can download the final Xcode project here.
Editor’s note: This is a sample chapter of our new book, Intermediate iOS 8 Programming with Swift. If you like this tutorial, you can check out the book here or get the starter package of our Swift book package.
Core Data file’s Location iOS 10
original source : https://stackoverflow.com/questions/39722844/core-data-files-location-ios-10
I tested it on XCode 8 Swift 3 OS macOS Sierra
IOS 10
In Your Appdelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
print(urls[urls.count-1] as URL)
return true
}
1. The constant .documentDirectory
says we are looking for Document directory
2. The constant .userDomainMask
to restrict our search to our application’s sandbox.
output
file:///Users/Ashok/Library/Developer/CoreSimulator/Devices/F629F99F-C745-46EB-8A11-01BC9FF1E592/data/Containers/Data/Application/3B373C93-71A2-46E9-8AF7-EF407C39429F/Documents/
Click on Go -> Go to Folder -> Paste Path -> Hit Enter

Then Go to Library -> Application Support -> filename.sqlite

Edited
OR
open your terminal and type find ~ -name 'HitTest.sqlite'
and hit enter.
Ashoks-MacBook-Pro:Desktop Ashok$ find ~ -name 'HitTest.sqlite'
/Users/Ashok/Library/Developer/CoreSimulator/Devices/F629F99F-C745-46EB-8A11-01BC9FF1E592/data/Containers/Data/Application/3B373C93-71A2-46E9-8AF7-EF407C39429F/Documents/HitTest.sqlite
From above output you can clearly see the path of your sqlite db
You can use DB Browser for SQLite to open.
Programmatically get path to Application Support folder
original source : https://stackoverflow.com/questions/8430777/programmatically-get-path-to-application-support-folder
Swift 4:
print(NSHomeDirectory())
or
print(FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first)
and
let yourString = String(FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first)
#1 answer : https://stackoverflow.com/a/33639227/3151712
How to check if a file exists in Documents folder?
original source : https://stackoverflow.com/questions/1638834/how-to-check-if-a-file-exists-in-documents-folder
Swift 3:
let documentsURL = try! FileManager().url(for: .documentDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: true)
… gives you a file URL of the documents directory. The following checks if there’s a file named foo.html:
let fooURL = documentsURL.appendingPathComponent("foo.html")
let fileExists = FileManager().fileExists(atPath: fooURL.path)
original source : https://stackoverflow.com/questions/16176911/nsurl-path-vs-absolutestring
Question 1:
What is the actual difference between these methods?
Let’s analyze this writing 6 lines of code – 3 for a local and 3 for http URL – and playing around with them a little bit.
Let’s create an NSURL
using the file://
scheme. If you ask yourself why there are 3 /
after file:
you should remember that a complete URL exists of a scheme (file://
and absolute or relative path (you can find more information on creating URLs in RFC 1808 on page 3). We use an absolute path which starts with a /
so that we end up with ///
.
NSURL *aLocalURL = [NSURL URLWithString:@"file:///Users/dennis/Desktop/"];
NSLog(@"absolute string: %@", aLocalURL.absoluteString);
NSLog(@"path: %@", aLocalURL.path);
Output:
absolute string: file:///Users/dennis/Desktop/
path: /Users/dennis/Desktop
So we see that absoluteString
still knows its scheme whereas path
doesn’t have this information anymore.
Note: path
is a file (directory) URL and as the docs state, the trailing slash it is stripped.
Now let’s take a look at remote URLs. With these type of URLs most people are more familiar. We create it using the same procedure as for local URLs. Our scheme is now http://
and our path
is www.apple.com/
.
NSURL *anHTTPURL = [NSURL URLWithString:@"http://www.apple.com/"];
NSLog(@"absolute string: %@", anHTTPURL.absoluteString);
NSLog(@"path: %@", anHTTPURL.path);
Output:
absolute string: http://www.apple.com/
path: /
Again, we see that the absolute string still knows its scheme but path
is now /
. So path
seems to be not an appropriate way when working with remote URLs.
However, when we have an URL
like http://www.apple.com/index.html
we get
absolute string: http://www.apple.com/index.html
path: /index.html
Reading the docs helps here, too:
Per RFC 3986, the leading slash after the authority (host name and port) portion is treated as part of the path.
So the path
is everything beginning (and including) at the slash after the authority
which is www.apple.com
in our case.
Question 2
Is there a time when one should be used over the other?
From the docs: (method: path
)
If this URL object contains a file URL (as determined with isFileURL), the return value of this method is suitable for input into methods of NSFileManager or NSPathUtilities.
In my opinion that sentence states clearly that you should use path
when you work with NSFileManager
or NSPathUtilities
.
Conclusion:
When you work with remote URLs you (generally) use absoluteString
, otherwise the result is not what you (generally) want.
When you work with local URLs use path
.
Sources:
http://www.ietf.org/rfc/rfc1808.txt
http://www.ietf.org/rfc/rfc3986.txt
NSURL Class Reference
내가 추가로 기입하는 내용
let documentsUrl = FileManager.default.urls(for: .applicationSupportDirectory, in:.userDomainMask).first!
let url = documentsUrl.appendingPathComponent(“QuestionModel.sqlite”)
print (“?? (url.path) ??n”)
print (“++ (url.absoluteString) ++n”)
위와 같은 코드를 이용하여 application support 폴더내 화일에 접근하려는 경우
url.path
?? /Users/owner/Library/Developer/CoreSimulator/Devices/7C444728-467E-4085-8E94-6298D30B68D1/data/Containers/Data/Application/055751E5-8656-4B84-AE74-99AB01522080/Library/Application Support/QuestionModel.sqlite ??
url.absoluteString
++ file:///Users/owner/Library/Developer/CoreSimulator/Devices/7C444728-467E-4085-8E94-6298D30B68D1/data/Containers/Data/Application/055751E5-8656-4B84-AE74-99AB01522080/Library/Application%20Support/QuestionModel.sqlite ++
와 같이 결과가 된다. path의 경우 space가 정상적으로 표시된다. absoluteString의 경우는 %20으로 표현된다.