Core Data 版本遷移經驗總結

發表於2016-04-03

大家在學習和使用Core Data過程中,第一次進行版本遷移的經歷一定是記憶猶新,至少我是這樣的,XD。弄的不好,就會搞出一些由於遷移過程中資料模型出錯導致的Crash。這裡總結了一下Core Data版本遷移過程中的經驗,希望對大家有用。

寫在前面

關於Core Data版本遷移,這兩篇文章都進行了分析,大家可以參考。

遷移準備

1) 選中工程中的 xcdaramodeId 檔案,Menu->Editor->Add Model Version

這一步新增完成之後,工程中的*xcdaramodeId* 檔案將會被展開,並且出現了新增加的Model檔案

2) 在Xcode右側的輔助工具欄中找到 Model Version, 選擇剛剛新增的Model檔案,這個時候你會發現Xcode目錄中,Model檔案上的綠色的勾選中了當前選擇的Model檔案

3) 在新的Model檔案中修改最新的Entities等資訊,記得也同時修改NSManagedObject Subclass對應的實現

4) 修改 NSPersistentStoreCoordinator部分實現:

輕量級遷移

當我們僅僅是對資料模型增加實體或者可選屬性時,上述步驟完成後執行程式碼進行遷移是奏效的。這個過程文件中叫做 Lightweight Migration,當我們進行輕量級遷移時,NSPersistentStoreCoordinator 會為我們自動推斷出一個Mapping Model。如果有更加複雜的改變,我們就需要自己去實現Mapping Mode。

新增Mapping Model過程: New File->CoreData->Mapping Model, 選擇我們需要進行Mapping的兩個Model,最終會生成一個 *xcmappingmodel* 檔案,大家可以開啟檔案,看到裡面生成了Model之間的對映。

官方文件中介紹如下的改變支援輕量級遷移:

  • 為Entity簡單的新增一個屬性
  • 為Entity移除一個屬性
  • 屬性值由 Optional Non-optional 之間轉換
  • 為屬性設定 Default Value
  • 重新命名Entity或者Attribute
  • 增加一個新的relationship 或者刪除一個已經存在的 relationship
  • 重新命名relationship
  • 改變relationship to-one to-many 等
  • 增加,刪除Entities
  • 增加新的 Parent 或者 Child Entity
  • 從Hierarchy中移除Entities

輕量級遷移不支援合併Entity的層級:比如在舊的Model中兩個已知的Entities沒有共享一個共同的Parent Entity,那麼在新的Model中它們也不能夠共享一個共同的Parent Entity。

在為屬性或者Entity等重新命名時,我們需要在Xcode右側輔助工具欄中找到 Versioning -> RenamingID,設定Reanaming Identifier為之前對應的名稱。

Mapping Models

如果我們對資料模型的修改不支援輕量級遷移,我們就需要像上文中所說的那樣,自己建立Mapping Model。

開啟建立好的xcmappingmodel檔案,我們發現可以增加或者修改對應的 Entity Mappings, Attibute Mappings 和 Relationship Mappings。

Core Data提供瞭如下一組變數允許我們進行配置:

有時候,我們不僅僅需要修改Entity的屬性或者關係,可以使用NSEntityMigrationPolicy自定義整個遷移的過程。繼承NSEntityMigrationPolicy實現遷移過程,然後選中對應的Entity Mapping,在Xcode右側輔助工具欄中找到Custom Policy,並設定為實現遷移對應的類名。

NSEntityMigrationPolicy

NSEntityMigrationPolicy目前提供了7個方法可供實現,它們的呼叫順序如下:

1) 當遷移將要開始時,會呼叫

2) 在舊資料上構建新的例項時呼叫

結束時呼叫

3) 構建新的RelationShips呼叫

結束時呼叫

4) 驗證,儲存資料呼叫

5) 遷移結束時呼叫

遷移過程

這裡分享的是自己專案中資料自定義遷移的整個過程,並附上部分程式碼實現邏輯。專案中採用的是漸進式遷移,漸進式遷移的概念在自定義 Core Data 遷移一文中有介紹:

1) 判斷本地SQLite資料庫檔案是否存在,不存在直接退出整個遷移。

2) 檢測當前本地資料庫和資料模型是否一致,如果一致就退出遷移。

3) 取得當前資料庫儲存時用的資料模型,如果獲取不到或者獲取失敗,退出遷移。

4) 取得當前工程中所有資料模型對應的managedObjectModel用於遷移,如果獲取的結果少於兩個就退出遷移。

5) 從所有的managedObjectModel中遍歷出最終使用的Model和當前資料庫採用的Model之間的所有Model,按照version順序構建一個新的 Model list,確保第一個是sourceModel,最後一個是當前需要使用的managedObjectModel。

6) 對生成的這個Model list進行迴圈,開始漸進式遷移。

7) 構建Model list中相鄰兩個Model之間的NSMappingModel例項,用做遷移。

8) 終於可以開始進行遷移了,XD

9) 建立一個新的檔案路徑用來儲存遷移過程中的資料檔案

10) 使用上文中的 modelA 和 modelB 構建一個 NSMigrationManager 例項,使用

方法進行遷移,其中 toDestinationURL引數是我們在步驟9中建立的路徑。如果migrate失敗,就退出整個遷移過程。

11) 資料替換 1.把原始的source檔案移動到新的backup資料夾中 2.使用步驟9中檔案下生成的遷移之後的資料檔案移動到原始的資料的路徑下 3.刪除backup

12) 回到步驟7,進行下一次迭代遷移,直到結束

遷移除錯

我們可以在Xcode中設定啟動引數 -com.apple.coredata.ubiquity.logLevel 3 或者 -com.apple.CoreData.SQLDebug 1, 這樣在程式執行時,控制檯將會列印更多Core Data使用中的資訊,包括呼叫的SQL語句。


相關文章