Search code examples
iosobjective-ccore-datacore-data-migration

Core Data - Lightweight migration doesn't work


I am new to Core Data, and I am currently maintaining an application using Core Data.

In the need of publishing a new release of the application soon, I have to add en Entity to the data model.

I have followed this tutorial Lightweight tutorial which was very useful but also I have read all the Apple documentation but also this amazing article Core Data Migration in order to understand globaly how it works.

Although I had to add only one entity to the data model, I heard that a Lightweight migration was OK in this situation.

It's only 1 new Entity (without attributes) that I have to link to the already existing parent Entity.

What I have done so far :

  • The application is currently on the version 3 of the datamodel
  • I have created a new data model (version 4) from the version 3
  • I have chosen data model version 4 as current data model
  • I have created my new Entity (whithout attribute), and linked it to the parent Entity.
  • I have created the generated class object
  • Then I modified my UI

Build and run, it works, cool. BUT when I download the current version from the AppStore, and when I install the new recently made Archive/IPA from TestFlight, (install over the old one -> migration scenario) the Application run without my new Entity/Datamodel.

From the Apple documentation, it is very clear that adding Entity is supported by Core Dara for Lightweight Migration.

I know this is not an easy process, but I feel like I have followed everything perfectly.

How can I test the migration without each time archive, publish on TestFlight etc...

If you need any additional informations in order to clearly understand my issue and/or write a more elaborated answer, feel free to ask in the comment and I will edit my question.

Thank you in advance.

EDIT :

Here are the code about the NSPersistentStoreCoordinator from the AppDelegate.

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    // The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it.
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }

    // Create the coordinator and store
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    NSURL *storeURL = [self persistentStoreURL];
    NSError *error = nil;
    NSString *failureReason = @"There was an error creating or loading the application's saved data.";
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:@{NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES} error:&error]) {
        // Report any error we got.
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        dict[NSLocalizedDescriptionKey] = @"Failed to initialize the application's saved data";
        dict[NSLocalizedFailureReasonErrorKey] = failureReason;
        dict[NSUnderlyingErrorKey] = error;
        error = [NSError errorWithDomain:@"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
        // Replace this with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        DDLogError(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    return _persistentStoreCoordinator;
}

I don't know how can I effectively know by tests or logs that CoreData use the new data model (version 4) and has performed the migration successfully.

I know it works when I build from xCode but it's not the same situation than an update from the AppStore.


Solution

  • To set up an app for a lightweight migration, you need to insert the following lines into your CoreData framework where the Persistent Store is declared. These settings enable the options that support lightweight migrations (these are from a Swift 3.0 app so they may vary a bit if you're in 2.3):

    NSMigratePersistentStoresAutomaticallyOption as NSObject: true                 
    NSInferMappingModelAutomaticallyOption as NSObject: true 
    

    Once these lines are in place, CoreData will perform lightweight migrations correctly whenever they're required, including adding new entities, attributes, and relationships so you should be OK as long as you don't do anything that requires more action on your part - like changing the name of an entity or property.