当CoreData中的Entity,Property或者Relationship发生改变以后,默认情况下面,在尝试调用CoreData的时候,程序会异常退出,具体是在:
除了上面的修改,还需要版本化xxx.xcdatamodel文件,在Xcode3.2上是在Design-Data Modal-Add Model Version,在新的xcdatamodal文件中修改,并设置为当前版本(在Design-Data Modal-Set Current Version)最后一步,需要指定使用新的xcdatamodal文件:
- if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl
- options:nil error:&error]) {
- // Update to handle the error appropriately.
- NSLog(@"[persistentStoreCoordinator] Unresolved error %@, %@", error, [error userInfo]);
- exit(-1); // Fail
- }
这个问题容易理解,我们就是通过一个ManagerdObjectModel(具体对应xcode里面的xxx.xcdatamodel文件,下面简称mom)来访问具体的存储数据,这里是xxx.sqlite文件,mom有一个hash table保存这个sqlite文件中的所有数据类型,版本等,当发现不匹配了就返回错误,如果想简单起见,可以在这里删除旧的数据,重新load一遍:
这里在第二次add失败后抛出异常,也可以改成其他的错误返回, 也可以使用CoreData的迁移(Migration)来兼容旧的数据,下面介绍一下迁移的方法
- if(![fileManager removeItemAtPath:storePath error:&error]){
- [NSException raise:NSInternalInconsistencyException format:@"Failed to remove ecrupt sqlite file. Location:%@", NSStringFromSelector(_cmd)];
- }
- NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:@"im" ofType:@"sqlite"];
- if (defaultStorePath) {
- [fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL];
- }
- if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl
- options:options error:&error]){
- [NSException raise:NSInternalInconsistencyException format:@"Failed to addPersistentStoreWithType. Location:%@", NSStringFromSelector(_cmd)];
- }
如果CoreData的实体数据发生下面几种变化的情况:
- 增加一个属性
- 必选的(non-optional)属性变成可选的(optional)
- 可选的(optional)属性变成了必选的(non-optional),并且定义了默认值
可以通过简单的方法(轻量级迁移)使得我们可以直接使用新的mom文件来访问旧的sqlite文件,既在打开存储文件的之前打开自动迁移:
- NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],
- NSMigratePersistentStoresAutomaticallyOption,
- [NSNumber numberWithBool:YES],
- NSInferMappingModelAutomaticallyOption, nil];
- NSError *error;
- if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
- configuration:nil
- URL:storeUrl
- options:options error:&error]) {
- // Update to handle the error appropriately.
- exit(-1); // Fail
- }
- - (NSManagedObjectModel *)managedObjectModel {
- if (managedObjectModel != nil) {
- return managedObjectModel;
- }
- NSString *path = [[NSBundle mainBundle] pathForResource:@"xxx 2" ofType:@"mom" inDirectory:@"xxx.momd"];
- NSURL *momURL = [NSURL fileURLWithPath:path];
- return managedObjectModel;
- }
上述代码指定使用xxx 2.xcdatamodel初始化mom文件注:这一步不确定是否是必须的,似乎用一下代码也可以:
- - (NSManagedObjectModel *)managedObjectModel {
- if (managedObjectModel != nil) {
- return managedObjectModel;
- }
- NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"xxx" withExtension:@"momd"];
- managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
- return managedObjectModel;
- }
另外,还有一种情况
- 重命名了实体或者属性
需要在加载mom文件之后,打开存储文件之前调用如下代码:
NSEntityDescription *automobile = [[destinationModel entitiesByName] objectForKey:@"Automobile"]; [automobile setRenamingIdentifier:@"Car"]; NSPropertyDescription *paintColor = [[automobile attributesByName] objectForKey:@"paintColor"]; [paintColor setRenamingIdentifier:@"color"];
或者可以直接在mom编辑器里面设置,请参考
其他的变化我们需要使用Mapping的机制来完成数据的迁移,这里有两种方式可以选择(参考):
- 默认迁移
- 自定义迁移
默认迁移只需要做两步,第一步在前面已经做过了,就是在轻量级迁移中设置的参数,第二步需要一个map文件,生成方法可以参考,如果不生成该文件,在访问存储文件时成功,但在访问数据的时候会发生异常;
自定义迁移需要手动控制各个实体,字段的迁移方式,我还没有试过