3

when i started developing the app, I had a Core data model with 5 Entities (named Visitors, UnreadMessages, ContactStatuses, UserVCard and User). The app went live on app store.. no issue in that.. Now i had to add some requirement changes so the core data model changed minorly by having 2 more entities added to it (named AudioSupportedWindows and AudioMessages)

So according to a lot of articles, SO posts, and apple documentation, The way to migrate this was LightWeight migration so for that I added the following code

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,    
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

NSError *error;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];

if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType        configuration:nil URL:storeUrl options:options error:&error]) {
    // Handle error
    NSLog(@"Problem with PersistentStoreCoordinator: %@",error);
}

in my persistentStoreCoordinator method. But it always gives a Can't find model for source store error.

After that I started of with manual migration using a migration mapping according to this link Core Data - Default Migration ( Manual )

But when i run this I get both source and destination models but they are identical that is they both consisting on 5 entities. and i get this error The model used to open the store is incompatible with the one used to create the store

terribly em in deep trouble ryt now solving this… any help would be greatly appreciated.

Edit 1

- (NSManagedObjectModel *)managedObjectModel
{
    if (managedObjectModel != nil)
    {
        return managedObjectModel;
    }
    
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"UserData" withExtension:@"momd"];
    managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

    return managedObjectModel;
}
Community
  • 1
  • 1
Ahmed Z.
  • 2,329
  • 23
  • 52
  • 2
    You must never ever change the data model of your app after it has been deployed to users. You need to create a new version of the model so that they are both in the app. If you have changed it, you need to go back to a previous version of your code (with git or whatever you are using for versioning), or from a previous backup. Then try again with both models included in your app. – Marius Waldal Feb 12 '14 at 07:54
  • THats a really weird thing you are saying that never to change the data model.. there can be requirement changes or additions to the application.. you'll then definitely need to change the model. – Ahmed Z. Feb 12 '14 at 07:56
  • No, you are saying that your app is live on the app store. Then you presumably have multiple users using your app with your current data model. If you need to change that data model, you can't just change your current model, as that will disable your app from using the current core data store (since the data model no longer matches the store). What I am saying is that you need to create a new version (a copy) in xcode, and then change the copy. This way, your app now includes TWO versions of the data model: the one used in the apps your users have, and the new model you want to migrate to – Marius Waldal Feb 12 '14 at 07:59
  • 1
    What he said is that you must not change your data model but instead create a new version of it and modifying the new version. – HAS Feb 12 '14 at 08:02
  • ohk.. so Still the issue is of migrating the model to the changed model.. – Ahmed Z. Feb 12 '14 at 08:06
  • How is [self managedObjectModel] implemented? – Wil Shipley Feb 12 '14 at 11:47

4 Answers4

1

Make sure the original model and the new model are both included in your app, in a model bundle. You can’t just include the new model and expect it to migrate (although that would be cooler), it’s not the way it works.

Your new model should be marked as the “current model.” Your old one is so the old file can still be read. If there are no required new fields in the new model that weren’t in the old one, the lightweight translation should work.

Wil Shipley
  • 9,343
  • 35
  • 59
1

Looks like your model you think you have released is different from the one you actually did. To check what did you submit to iTC:

  • go to Organizer/Archives find the archive you submitted then 'Show in Finder'
  • find the model version file: VersionInfo.plist
  • open the plist have a look into the the hash value for each entity

Comparing the hash value with hash values of your current model (just create a fresh archive) you should be able to find the one which has changed.

tomi44g
  • 3,266
  • 1
  • 20
  • 28
  • the entities that are in both versions have same hash values.. the only difference in them is the entities that are added in the newer version. – Ahmed Z. Feb 12 '14 at 08:35
  • one more thing, idk if it matters or not, there are 4 files there instead of 3 **UserData.mom, UserData 2.mom, VersionInfo.plist and UserData 2.omo** – Ahmed Z. Feb 12 '14 at 08:36
  • In the VersionInfo.plist you should have two models: one with the original 5 entities and 'Model 2' with 7 entities. – tomi44g Feb 12 '14 at 09:15
1

This might be an issue I've run a few times. Download your app from the app store and run it so it creates the managed object store. Then in your xcode before instantiating your persistent store coordinator try the following:

// Model.momd/Model is the path of the previous model. Make sure it's correct
NSURL *oldUrl = [[NSBundle mainBundle] URLForResource:[NSString stringWithFormat:@"Model.momd/Model"] withExtension:@"mom"];
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:oldUrl];
NSLog(@"Old model version hashes: %@", model.entityVersionHashesByName);

// Change model with your model name
NSURL *currentModelUrl = [[NSBundle mainBundle] URLForResource:[NSString stringWithFormat:@"Model"] withExtension:@"momd"];
NSManagedObjectModel *currentModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:currentModelUrl];
NSLog(@"Current model version hashes: %@", currentModel.entityVersionHashesByName);



// storeUrl is the path to the persistent store, created by the app store version
NSDictionary *metadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:storeUrl error:nil];
NSLog(@"Store metadata: %@", metadata);

Metadata entity hashes should be identical to your old model version hashes. If they are not, then the original model you have and the one you've shipped with are different. You might need to find your old model in your source control repo (hope you have one), otherwise you can try changing those values by hand.

graver
  • 15,183
  • 4
  • 46
  • 62
  • just did this… no difference in 5 entities hash values, only difference is the newly added 2 entities in current model hash value. – Ahmed Z. Feb 12 '14 at 09:45
  • So the difference between the old model and the current model is exactly the 2 new entities, and the metadata is exactly as the old model ? – graver Feb 12 '14 at 10:29
  • Hm, then you shouldn't have that problem at all – graver Feb 12 '14 at 10:49
  • thats what is killing me… i can't seem to find any problem but it won't migrate – Ahmed Z. Feb 12 '14 at 10:51
0

Thank you everyone for the help… I solved it using lightweight migration.. what i did was delete my xcdatamodeld, recreate it from the one on App Store, make new database file, add new model version.. Somehow i have no clue how it got working…

but em happy it works :)

Ahmed Z.
  • 2,329
  • 23
  • 52