David Vincent Gagne
David Vincent Gagne

Reputation: 527

Core Data Lightweight Migration Xcode Crash

I'm trying to do what should be a very simple lightweight migration involving the addition of an Entity attribute.

In my AppDelegate I have:

lazy var persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "app")
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })
    return container
}()

I have tried creating a new .xcdatamodel and adding the Entity attribute there, then changing the Model Version current to this new data model. I have also tried simply adding the Entity attribute to my existing data model.

In both cases when I hit run, Xcode crashes without giving me the ability to read any of the console output, so I am at a loss on how to move forward. (I have done this dozens of times.)

Everything I've read seems to indicate that because adding an Entity attribute is a minor change, a lightweight migration should work, and that both shouldInferMappingAutomatically and shouldMigrateStoreAutomatically should default to true.

There are numerous explanations of how to perform a lightweight migration if using addPersistentStore but I'm not using that; I'm using loadPersistentStores and it seems like I'd have to refactor my entire app to change this (and, anyway, everything seems to indicate that loadPersistentStores is the new / approved way to handle Core Data).

Update

Based on some other SO posts, I've updated my lazy initialization to the following:

lazy var persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "app")
    let url = NSPersistentContainer.defaultDirectoryURL()
    let description = NSPersistentStoreDescription(url: url)
    description.shouldAddStoreAsynchronously = true
    description.shouldInferMappingModelAutomatically = true
    description.shouldMigrateStoreAutomatically = true
    description.isReadOnly = false
    container.persistentStoreDescriptions = [description]
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })
    return container
}()

I put a breakpoint right at the if let error = error and was able to capture the console before Xcode crashes. Here is the result:

CoreData: warning:  View context accessed for persistent container app with no stores loaded
CoreData: warning:  View context accessed for persistent container app with no stores loaded
CoreData: error: -addPersistentStoreWithType:SQLite configuration:(null) URL:file:///var/mobile/Containers/Data/Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Library/Application%20Support/ options:{
NSAddStoreAsynchronouslyOption = 1;
NSInferMappingModelAutomaticallyOption = 1;
NSMigratePersistentStoresAutomaticallyOption = 1;
NSReadOnlyPersistentStoreOption = 0;
}
... returned error Error Domain=NSCocoaErrorDomain Code=256 "The file couldn’t be opened." UserInfo={NSSQLiteErrorDomain=14, NSUnderlyingException=unable to open database file} with userInfo dictionary {
NSSQLiteErrorDomain = 14;
NSUnderlyingException = "unable to open database file";
}
(lldb)

But now I am (again) stuck. I cannot imagine why the app would be unable to open the database file and have no idea how to determine what's preventing it.

Upvotes: 1

Views: 1372

Answers (1)

David Vincent Gagne
David Vincent Gagne

Reputation: 527

Update

I removed the new code from my lazy initialization and returned it to simply:

lazy var persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "bartender")
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })
    return container
}()

I put the breakpoint at the same place and this time found this message in the console: Cannot migrate store in-place: Validation error missing attribute values on mandatory destination attribute

That led me to the idea of setting a Default Value in the new attribute of the Entity I'd updated, and now Xcode is no longer crashing, so it seems the problem is fixed!

Upvotes: 2

Related Questions