小結CoreData的Migration

當CoreData中的Entity,Property或者Relationship發生改變以後,默認情況下面,在嘗試調用CoreData的時候,程序會異常退出,具體是在:
  1. if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl   
  2.                         options:nil error:&error]) {  
  3.         // Update to handle the error appropriately.  
  4.         NSLog(@"[persistentStoreCoordinator] Unresolved error %@, %@", error, [error userInfo]);  
  5.         exit(-1);  // Fail  
  6.     }  

這個問題容易理解,我們就是通過一個ManagerdObjectModel(具體對應xcode裏面的xxx.xcdatamodel文件,下面簡稱mom)來訪問具體的存儲數據,這裏是xxx.sqlite文件,mom有一個hash table保存這個sqlite文件中的所有數據類型,版本等,當發現不匹配了就返回錯誤,如果想簡單起見,可以在這裏刪除舊的數據,重新load一遍:

  1. if(![fileManager removeItemAtPath:storePath error:&error]){  
  2.             [NSException raise:NSInternalInconsistencyException format:@"Failed to remove ecrupt sqlite file. Location:%@", NSStringFromSelector(_cmd)];  
  3.         }  
  4.           
  5.         NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:@"im" ofType:@"sqlite"];  
  6.         if (defaultStorePath) {  
  7.             [fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL];  
  8.         }     
  9.           
  10.         if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl   
  11.                                                             options:options error:&error]){  
  12.             [NSException raise:NSInternalInconsistencyException format:@"Failed to addPersistentStoreWithType. Location:%@", NSStringFromSelector(_cmd)];  
  13.         }  
這裏在第二次add失敗後拋出異常,也可以改成其他的錯誤返回,也可以使用CoreData的遷移(Migration)來兼容舊的數據,下面介紹一下遷移的方法

如果CoreData的實體數據發生下面幾種變化的情況:

  • 增加一個屬性
  • 必選的(non-optional)屬性變成可選的(optional)
  • 可選的(optional)屬性變成了必選的(non-optional),並且定義了默認值

可以通過簡單的方法(輕量級遷移)使得我們可以直接使用新的mom文件來訪問舊的sqlite文件,既在打開存儲文件的之前打開自動遷移:

  1. NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],   
  2.                              NSMigratePersistentStoresAutomaticallyOption,   
  3.                                                          [NSNumber numberWithBool:YES],   
  4.                              NSInferMappingModelAutomaticallyOption, nil];    
  5.    
  6.     NSError *error;  
  7.     if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType   
  8.                                                       configuration:nil   
  9.                                                                 URL:storeUrl   
  10.                                         options:options error:&error]) {  
  11.         // Update to handle the error appropriately.  
  12.         exit(-1);  // Fail  
  13.     }  
除了上面的修改,還需要版本化xxx.xcdatamodel文件,在Xcode3.2上是在Design-Data Modal-Add Model Version,在新的xcdatamodal文件中修改,並設置爲當前版本(在Design-Data Modal-Set Current Version)
最後一步,需要指定使用新的xcdatamodal文件:


  1. - (NSManagedObjectModel *)managedObjectModel {  
  2.       
  3.     if (managedObjectModel != nil) {  
  4.         return managedObjectModel;  
  5.     }  
  6.   
  7.   
  8.     NSString *path = [[NSBundle mainBundle] pathForResource:@"xxx 2" ofType:@"mom" inDirectory:@"xxx.momd"];  
  9.     NSURL *momURL = [NSURL fileURLWithPath:path];  
  10.       
  11.     return managedObjectModel;  
  12. }  
上述代碼指定使用xxx 2.xcdatamodel初始化mom文件注:這一步不確定是否是必須的,似乎用一下代碼也可以:
  1. - (NSManagedObjectModel *)managedObjectModel {  
  2.       
  3.     if (managedObjectModel != nil) {  
  4.         return managedObjectModel;  
  5.     }  
  6.   
  7.   
  8.     NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"xxx" withExtension:@"momd"];  
  9.     managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];      
  10.       
  11.     return managedObjectModel;  
  12. }  
另外,還有一種情況 重命名了實體或者屬性

需要在加載mom文件之後,打開存儲文件之前調用如下代碼:

NSEntityDescription *automobile = [[destinationModel entitiesByName] objectForKey:@"Automobile"];
[automobile setRenamingIdentifier:@"Car"];
NSPropertyDescription *paintColor = [[automobile attributesByName] objectForKey:@"paintColor"];
[paintColor setRenamingIdentifier:@"color"];

或者可以直接在mom編輯器裏面設置,請參考

其他的變化我們需要使用Mapping的機制來完成數據的遷移,這裏有兩種方式可以選擇(參考):

  • 默認遷移
  • 自定義遷移

默認遷移只需要做兩步,第一步在前面已經做過了,就是在輕量級遷移中設置的參數,第二步需要一個map文件,生成方法可以參考,如果不生成該文件,在訪問存儲文件時成功,但在訪問數據的時候會發生異常;

自定義遷移需要手動控制各個實體,字段的遷移方式,我還沒有試過

原文地址

發佈了21 篇原創文章 · 獲贊 6 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章