开发者

Core Data automatic lightweight migration - switching from unversioned to versioned data model

开发者 https://www.devze.com 2023-04-12 05:37 出处:网络
I am trying to perform a lightweight migration, but I am having a problem because of the way I created my initial datamodel. The initial data model was not versioned, so now the following co开发者_如何

I am trying to perform a lightweight migration, but I am having a problem because of the way I created my initial datamodel. The initial data model was not versioned, so now the following co开发者_如何学Pythonde:

-(NSManagedObjectModel *)managedObjectModel {

    //NSLog(@"%s", __FUNCTION__);
    if (managedObjectModel != nil) {
        return managedObjectModel;
    }
    //managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];

    NSString *mainPath = [[NSBundle mainBundle] pathForResource:@"myDatabase" ofType:@"momd"];

    NSURL *mainMomURL = [NSURL fileURLWithPath:mainPath];
    managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:mainMomURL];
    return managedObjectModel;
}

returns the error: * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[NSURL initFileURLWithPath:]: nil string parameter'

I am pretty sure that this is because the initial data model - the one I deployed in my app to many people already - had the mom extension as opposed to the momd extension. But, if I take this out and revert to

managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];

I get the error: Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Can't merge models with two different entities named...

I am hoping this is not the first time someone has come across this situation... Is there something I can do so that I can have a successful migration for all of my current users?


Okay, making progress. As per Yuji's answer in this link: Can't find momd file: Core Data problems

, I decided to go with the line:

managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];

After installing the old version on the device, adding some data, doing a clean build with the new version and then installing the new version on the device, everything updated properly. About to try again in the simulator and with my other targets. It's crazy, do you sometimes feel like you do the same thing you did and get different results sometimes? I will post an update once I get further along....

EDIT: Some interesting developments. As it stands this project started out as one of my apps, and I added in another app with similar code (as a separate target) for code reuse, after both apps were deployed to the app store. Since their databases were essentially the same, I just used the same xcdatamodel for both. Which worked fine until... I started to handle this migration issue. Turns out that the above code for managedObjectModel does work for the orginal target in the project, but not for the new target.

Then, I found this comment by Marcus Zarra:

He probably either renamed the model or set up a version, both of which will leave an old compiled .mom file in the build directory. That is the #1 cause of this error I have seen.

in this link: Core Data: Error, “Can't Merge Models With Two Different Entities Named 'foo' ”

Well, maybe we are getting somewhere here now. The question is - do I now need to bring in my other, original, data model to the project, and update IT as well??? Where do we go from here?

EDIT: Okay, I think I have made some good progress on this issue. Please feel free to correct me on any of the following. But, from what I have learned so far:

The Bundle Name should stay the same, or there will be problems with the migration. This means, in my understanding, probably leaving the product name as is. But, it seems like changing the Bundle Display Name (which is different from the Bundle Name, and is also set in the app-info.plist file) doesn't hurt things, and in fact accomplishes the purposes or changing the Bundle Name in the first place.

Also (my original question!), it is TOTALLY fine to switch from an unversioned data model to a versioned data model, and in fact, it is expected that this is what generally happens with the first migration. So no problem there.

Another lesson learned - the data model name and the .sqlite file name are not necessarily the same! One of my (many) mistakes was using the .sqlite file name when looking for the momd file. WHen you look for the momd file (when setting the managedObjectModel in the app delegate) - use the name of the xcdatamodel file! Along those lines, I wasn't sure if during my migration I should use "mergedModelFromBundles" or "initWithContentsOfURL". Once I had the correct file names, initWithContentsOfURL worked fine (I do still have some testing to do, but I have gotten it to work with both apps targets, in the simulator and on the device. Score.

A word about xcdatamodels and xCode 4 - what a headache. For some reason I cannot delete interim/unused/unneeded data model versions in xCode 4. So, I had to do a lot of fancy footwork to get these JUST right, including deleting the models themselves (references only), making changes by using "Show Package Contents" in the Finder, and adding the models back in. One should be VERY careful when doing this. One very interesting thing I found is that I DID need two xcdatamodels, one for each of the app targets that I am working with, and that the titles of xcdatamodel needs to match that of the previously deployed version for migration to work. Not only that, but the current model needs to be the one without a number - it needs to match perfectly the name of the model in my deployed app.

This was really tricky because xCode 4 did not always want to cooperate when I was renaming models and setting different models to current version. One interesting thing was that, when I had to set a model that was underneath another model in the tree as the current model, xcode did not like that during runtime. So I literally had to go into the .xcodeproj file in Finder (with app closed), Show Package Contents, edit the project.pbxproj file, and change the order of the datamodels to put the current one at the top of the list.

Well, I think that is mostly everything. If I think of anything else I will add it here. Still want to test this a little more, but I am hoping some of the things I learned will help someone. I know I did a lot of hackish things, but desperate times call for desperate measures, and when we know better we do better... Hope this helps.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号