Deploy App with Pre-Populated Core Data

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



Leave a reply



Submit