Deploy app with pre-populated Core Data
This is the solution I found:
Step 1
Populate your Core Data
in another app and get files' path using this code:
let paths = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
print(documentsDirectory)
Step2
Drag your 3 files with .sqlite
extension into your xCode project. (Be sure to select Add to targets
option).
Step3
Create function to check app's first run.
func isFirstLaunch() -> Bool {
let hasBeenLaunchedBeforeFlag = "hasBeenLaunchedBeforeFlag"
let isFirstLaunch = !UserDefaults.standard.bool(forKey: hasBeenLaunchedBeforeFlag)
if (isFirstLaunch) {
UserDefaults.standard.set(true, forKey: hasBeenLaunchedBeforeFlag)
UserDefaults.standard.synchronize()
}
return isFirstLaunch
}
Step4
Copy this in AppDelegate
:
func getDocumentsDirectory()-> URL {
let paths = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
return documentsDirectory
}
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "ProjectName")
let appName: String = "ProjectName"
var persistentStoreDescriptions: NSPersistentStoreDescription
let storeUrl = self.getDocumentsDirectory().appendingPathComponent("FileName.sqlite")
if UserDefaults.isFirstLaunch() {
let seededDataUrl = Bundle.main.url(forResource: "FileName", withExtension: "sqlite")
try! FileManager.default.copyItem(at: seededDataUrl!, to: storeUrl)
}
let description = NSPersistentStoreDescription()
description.shouldInferMappingModelAutomatically = true
description.shouldMigrateStoreAutomatically = true
description.url = storeUrl
container.persistentStoreDescriptions = [description]
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
Step 5
If you want to delete your new Core Data
files, use this function:
func deleteFiles() {
let fileManager = FileManager.default
let documentsUrl = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first! as NSURL
let documentsPath = documentsUrl.path
do {
if let documentPath = documentsPath {
let fileNames = try fileManager.contentsOfDirectory(atPath: "\(documentPath)")
print("all files in cache: \(fileNames)")
for fileName in fileNames {
if (fileName.contains("YourFileName")) {
let filePathName = "\(documentPath)/\(fileName)"
try fileManager.removeItem(atPath: filePathName)
}
}
let files = try fileManager.contentsOfDirectory(atPath: "\(documentPath)")
print("all files in cache after deleting images: \(files)")
}
} catch {
print("Could not clear temp folder: \(error)")
}
}
Any way to pre populate core data?
Here's the best way (and doesn't require SQL knowledge):
Create a quick Core Data iPhone app (Or even Mac app) using the same object model as your List app. Write a few lines of code to save the default managed objects you want to the store. Then, run that app in the simulator. Now, go to ~/Library/Application Support/iPhone Simulator/User/Applications. Find your application among the GUIDs, then just copy the sqlite store out into your List app's project folder.
Then, load that store like they do in the CoreDataBooks example.
How can I use a pre-populated core data DB on my device
Take a look at this question:
Any way to pre populate core data?
iOS ship application with pre populated sqlite database
In iOS you can add the database into the Project Supporting files. This will be added in with the binary, which you can then access and copy it across.
To get the location of the pre-populated database from NSBundle:
let databasePath = NSBundle.mainBundle().URLForResource("databaseName", withExtension:"sqlite3");
Get the URL of the Documents Directory using NSFileManager:
//Should have an error pointed in case there is an error.
let documentsDirectory = NSFileManager.defaultManager().URLForDirectory(NSSearchPathDirectory.DocumentDirectory, inDomain:NSSearchPathDomainMask.UserDomainMask, url:nil, shouldCreate:false, error:nil);
Finally copy the file:
if let source = databasePath, destination = documentsDirectory
{
destination = destination.URLByAppendingPathComponent("database.sqlite3")
var result = NSFileManager.defaultManager().copyItemAtURL(source, toURL:destination, error:nil)
//Should have an error pointer, check that the result is true. If not check error.
}
Related Topics
App Crashes When Playing Audio on iOS13.1
Why Does an @Objc Enum Have a Different Description Than a Pure Swift Enum
How to Enumerate a Slice Using the Original Indices
Generate an Rsa Public/Private Key Pair
Changing Value in Nested Dictionary in Swift
How to Nskeyedunarchiver.Unarchiveobject
Saving Array to Realm in Swift
Generate an Integer Binary Representation Using Swift
Why Can't I Change Variables in a Protocol Extension Where Self Is a Class
Why Does Swift Provide Both a Cgrect Initializer and a Cgrectmake Function
Why Do I Still Need to Unwrap Swift Dictionary Value
Difference Between Println and Print in Swift
Transparent Nscollectionview Background
Dispatchqueue.Main.Asyncafter Is Inaccurate