Alex
Alex

Reputation: 111

Loading Core Data database created by iOS app into different Xcode application

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

Answers (2)

Alex
Alex

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

Lou Franco
Lou Franco

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

Related Questions