Reputation: 111
I have previously created an iOS app that saves data to a database. I have copied data off the app and now have three files:
MyData.sqlite, MyData.sqlite-shm, and MyData.sqlite-wal
I am trying to create a command-line utility in Xcode that will access the data from those databases. I have added CoreData to the command line utility project, and am able to create a new database. What I want though is to load the database I have exported from the app.
I have found a previous question from someone: Migrate Core Data database from one app to another
However, their answer does not work for me. This line:
let storeUrl = FileManager.default.urls(for: .documentDirectory, in:.userDomainMask).first!.appendingPathComponent(databaseName + ".sqlite")
gives this error:
expression produced error: error: /var/folders/cc/r_54b90515v_m6t41vg9lg000000gp/T/expr14-6084fa..swift:1:65: error: use of undeclared type 'Foundation'
Swift._DebuggerSupport.stringForPrintObject(Swift.UnsafePointer<Foundation.URL>(bitPattern: 0x1004fc2f0)!.pointee)
I feel like I must be missing a simple answer to this problem. Is there an easy way to transplant the Core Data database information from one app to another?
EDIT: Thanks to Lou Franco below I have made some progress. I now have:
var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "MyData")
let storeUrl = URL(fileURLWithPath: "/Path/To/Data/MyData.sqlite")
container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: storeUrl)]
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
However I now get a whole bunch of output summarised by "Persistent store migration failed, missing mapping model."
I was hoping by setting the container with the current Core Data initially I could somehow let the program know what to expect of what it is loading (the data model is the same) but it seems to fail regardless. I noticed in the error messages:
NSInferMappingModelAutomaticallyOption = 1;
NSMigratePersistentStoresAutomaticallyOption = 1;
Is there a way of having the program know that the data it is loading conforms to the Core Data model I already set? It just has to load the data from the file.
Upvotes: 1
Views: 710
Reputation: 111
Thanks to some of the recommendations from Lou Franco, I have found my way to a working solution. I grabbed the .momd file from the original app by archiving it and exploring the exported .app file in the .xcarchive. Here is a minimal example that loads data from an existing sqlite database at "/Path/To/Data/MyData.sqlite" using the data model from "/Path/To/Data/MyData.momd". It simply grabs all of the unique session IDs:
import Foundation
import CoreData
let storePath = "/Path/To/Data/MyData.sqlite"
let storeURL = URL(fileURLWithPath: storePath)
let modelPath = "/Path/To/Data/MyData.momd"
let modelUrl = URL(fileURLWithPath: modelPath)
let mom = NSManagedObjectModel(contentsOf: modelUrl)!
let psc = NSPersistentStoreCoordinator(managedObjectModel: mom)
let managedObjectContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.mainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = psc
try psc.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: nil)
let request: NSFetchRequest<Session> = Session.fetchRequest()
request.sortDescriptors = [NSSortDescriptor(key: "uniqueSessionID", ascending: true)]
let context = managedObjectContext
do {
let dbReturn = try context.fetch(request)
print(dbReturn)
}
Upvotes: 0
Reputation: 89142
This line:
let storeUrl = FileManager.default.urls(for: .documentDirectory, in:.userDomainMask).first!.appendingPathComponent(databaseName + ".sqlite")
Doesn't work for command-line utilities. It's for apps.
You are going to have to get a path some other way (command line arg, hard-code, relative to utility, etc)
For example:
URL(fileURLWithPath: FileManager.default.currentDirectoryPath).appendingPathComponent("YOURFILE"))
Upvotes: 1