I'm trying to ship my app with Core Data
already populated. I found some links where they explain how to do it, but either it doesn't work or the answers are very old. I followed this post but it doesn't work. A solution could be to import .sqlite
files to the app folder and then copy them to device's file system, but I can't figure out how to do it. Are there any ways to pre-populate my Core Data with existing entities and records?
Asked
Active
Viewed 1,796 times
5

Andrea Toso
- 287
- 4
- 12
-
2Possible duplicate of [Any way to pre populate core data?](https://stackoverflow.com/questions/2230354/any-way-to-pre-populate-core-data) – Tamás Sengel Dec 19 '17 at 18:08
-
@the4kman I can't figure out how to load the store to the app. – Andrea Toso Dec 19 '17 at 18:11
3 Answers
4
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)")
}
}

Andrea Toso
- 287
- 4
- 12
-
3Correct me if I'm wrong, but doesn't this solution duplicate the amount of disk space the app is using for the data? The seeded data is grabbed from the resource bundle and then injected into the core data db. That data now sits in two places on disk. If I'm going to be deploying an app with 250Mb of data, I don't want to duplicate this data on disk. – andrewz Mar 06 '20 at 00:37
0
My step 4 version:
private func isFirstLaunch() -> Bool {
let isFirstLaunchKey = "firstLaunch"
let userDefaults = UserDefaults.standard
let isFirstLaunch = !userDefaults.bool(forKey: isFirstLaunchKey)
if isFirstLaunch { userDefaults.setValue(true, forKey: isFirstLaunchKey) }
return isFirstLaunch
}
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "YourProjectCDName")
if isFirstLaunch() {
if let storeUrl = container.persistentStoreDescriptions.first?.url,
let seededDataUrl = Bundle.main.url(forResource: "YourProjectCDName", withExtension: "sqlite") {
do {
try container.persistentStoreCoordinator.replacePersistentStore(
at: storeUrl,
destinationOptions: nil,
withPersistentStoreFrom: seededDataUrl,
sourceOptions: nil,
ofType: NSSQLiteStoreType)
} catch {
print(error.localizedDescription)
}
} else {
fatalError("Cannot unwrap URLs!")
}
}
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()

Gil
- 21
- 1