Core Data託管對象模型的遷移

修改託管對象模型

在應用程序的進行過程當中,其託管對象模型也可能須要進行修改。對於一些比較簡單的修改,諸如設定屬性的默認值、設定驗證規則、使用獲取請求模板等,是能夠直接實施的。而對於另一些更爲結構化的修改,則須要把持久化存儲區遷移到新的模型版本才行。假如沒有提供遷移數據所須要的映射與設定,那麼應用程序就會崩潰。html

引起模型不兼容錯誤

在託管對象模型中添加另一個新的實體,而且在新的實體中添加一些新的屬性。
從新運行應用程序,你會發現程序會崩潰掉。ios

對於處在開發初期的應用程序來講,這種崩潰算不上什麼大的問題,咱們只須要吧程序刪除了並從新運行一次就行了。刪除以後,在次運行應用程序時,它會按照最新的模型來建立持久化存儲區。這樣一來,存儲區就能夠和模型相兼容了,因而應用程序也就不會再次崩潰了。可是,這樣作也會失去存儲區裏原有的數據。對於已經在App Store上架的程序來講,這讓人沒法接受。有好幾種辦法均可以遷移現有的持久化存儲區,而遷移路徑則是由變動的複雜程度以及是否使用iCloud等因素來決定的。不管採用哪一種遷移辦法,咱們都必須首先熟悉「模型版本控制」。數據庫

添加模型版本

按照如下步驟來添加模型版本:swift

一、選中Model.xcdatamodeld
二、點擊Editor> Add Model Version...菜單項
三、點擊Finish,將Model2用做版本名稱。app

如今項目中會有兩個版本的模型了。如圖:測試

兩個版本模型

Model2.xcdatamodel這個新的模型的內容一開始便與Model.xcdatamodel徹底相同。ui

咱們如今選中Model2.xcdatamodel這個新的模型,在這個新的模型中添加Measurement實體,建立名叫abc的屬性,並將其類型設置爲String。spa

添加了新的版本模型以後,必須將其設置爲當前版本,而後才能讓應用程序使用它。線程

選中Model.xcdatamodeld在右側將 Current Model Version設置爲Model2.如圖:版本控制

Current Model Version

若是想正常運行應用程序,那麼咱們還須要配置好遷移選項,告訴Core Data應該如何去遷移。要是如今就去運行應用程序的話,那天然仍是會發生Store is incompatible(存儲區不兼容)錯誤。

輕量級的遷移方式

把新的模型設置爲當前版本以後,必須遷移現有的持久化存儲區,只有這樣,才能正常使用新模型。這是由於,持久化存儲區協調器會試着使用新的模型來打開原有的存儲區,可是原有的存儲區是用舊版本的模型建立的,因此會出現錯誤。在向NSPersistentStoreCoordinator添加存儲區的時候,只須要將下列選項放在NSDictionary裏面傳過去,便可自動完成存儲區的遷移工做:

若是傳給NSPersistentStoreCoordinatorNSMigratePersistenStoresAutomaticallyOptionYES,那麼Core Data 就會試着把低版本的持久化存儲區遷移到最新版本的模型。

若是傳給NSPersistentStoreCoordinatorNSInferMappingModelAutomaticallyOption是YES,那麼Core Data 就會試着以最爲合理地方式自動推斷出源模型實體中的某個屬性到底對應於「目標模型實體」中的哪個屬性。

打開CoreDataHelper.swift同時添加一個屬性在這個類中。

lazy var options: NSDictionary?

Right now, you’re setting up the persistent store with no options for default behavior. You’ll use the options dictionary to set the necessary flags.

// 這裏是添加的部分,名如其意,當咱們須要自動版本遷移時,咱們須要在addPersistentStoreWithType方法中設置以下options
let options = [NSInferMappingModelAutomaticallyOption: true, NSMigratePersistentStoresAutomaticallyOption: true]

var error: NSError? = nil
persistentStoreCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: options, error: &error)

從新運行應用程序,此次應該就不會奔潰了。
從如今開始,只須要把新模型設爲當前版本並啓動啓用輕量級遷移,CoreData就會無縫的完成遷移過程。

默認的遷移方式

有時候咱們須要比輕量級更爲精細的控制手段。比方說,咱們要把實體A替換爲另一個實體B,而且還想把A實體中的屬性abc遷移到實體B中的xyz屬性上面。abc中已有數據也要遷移到xyz屬性。爲了完成這些需求,開發者須要建立模型映射,以便指明映射關係。在添加持久化存儲區時,即使 NSInferMappingModelAutomaticallyOption選項設置爲true,Core Data 也仍是會先檢測有沒有文件,若是有的話,那麼在執行自動推斷以前,它會先試着使用這個文件來遷移。在測試映射模型以前,建議先禁用該選項,這樣才能肯定映射模型是否是已經付諸實用而且可以正常運做了。

請按照下列步驟修改xcdatamodel,以添加新的映射模型:

  1. 確保Data Model 處於選中狀態

  2. 點擊 File > New > File ... 菜單項

  3. 選擇 iOS > Core Data > Mapping Model , 並點擊Next 按鈕

  4. 把 Model2.xcdatamodel 選爲Source Data Model ,並點擊Next按鈕

  5. 把 Model3.xcdatamodel 選爲Target Data Model ,並點擊Next按鈕

  6. 將mapping model 的名稱設爲Model2toModel3 ,並將其保存

  7. 選中Model2toModel3.xcmappingmodel

如今你將看到以下圖的界面:

Xcode 目前呈現出來的這套映射是Coredata 以最合理的方式推斷出來的。在界面的左方,會看到 ENTITY MAPPINGS 字樣,它下面列出了源實體與目標實體之間的映射。實體映射時所採用的命名標準是SourceToDestination (源實體命名到目標實體命名)。有時候就會出現某一個實體並無與之對應的源實體,多是應爲沒有出如今源模型裏。這時你須要手動映射。

在上圖的右側你能夠看到各類設置。

若是要實現更爲複雜的遷移方式,那麼能夠在 Custom Policy 文本框中輸入類名,這個類應該是NSEntityMigrationPolicy的子類。該子類中,能夠經過複寫createDestinationInstancesForSourceInstance方法而操做待遷移的數據。比方說,能夠攔截abc這個屬性的值,將其中每一個單詞的首字母改成大寫,而後再把修改過的值遷移到xyz 屬性。

底部的Source Fetch選項能夠經過謂詞(Filter Predicate 文本框中輸入)限定遷移過來的數據量。假如只想把舊數據中的一部分遷移過來,那麼這個選項就頗有用。此處的謂詞格式與一般代碼中編寫的謂詞類似,只不過要用 $source變量來表示源數據。比方說,若是把abc屬性值爲 nil 的源數據排除掉,那麼謂詞能夠寫成 $source.abc != nil

選定ENTITY MAPPINGS字樣下方的ItemToItem實體,並觀察屬性映射內容,會看到目標實體中的每一個屬性都設置對應的Value Expression

當你要升級你的數據模型到新版,你將先選擇一個基準模型。對於輕量級遷移,持久化存儲會爲你自動推斷一個映射模型。然而,若是你對新模型所作的修改並不被輕量級遷移所支持,那麼你就須要建立一個映射模型。一個映射模型須要一個源數據模型和一個目標數據模型。 NSMigrationManager 可以推斷這兩個模型間的映射模型。這使得它很誘人,可用來一路建立每個之前的模型到最新模型之間的映射模型,但這很快就會變成一團亂麻。對於每個新版模型,你須要建立的映射模型的量將線性增加。這可能看起來不是個大問題,但隨之而來的是測試這些映射模型的複雜度大大提升了。
想像一下你剛剛部署一個包含版本 3 的數據模型的更新。你的某個用戶已經有一段時間沒有更新你的應用了,這個用戶還在版本 1 的數據模型上。那麼如今你就須要一個從版本 1 到版本 3 的映射模型。同時你也須要版本 2 到版本 3 的映射模型。當你添加了版本 4 的數據模型後,那你就須要建立三個新的映射模型。顯然這樣作的擴展性不好,那就來試試漸進式遷移吧。

經過遷移管理器來遷移數據

除了經過NSPersistentStoreCoordinator來遷移存儲區以外,還能夠經過採用遷移管理器來作。遷移管理器可使開發者全權掌握遷移過程當中建立的文件,從而令他們可以按本身的方式來靈活處理遷移中的種種問題。使用遷移管理器的一個好處就是能夠向用戶報告遷移進度,使用戶知道應用程序哪次會啓動的比較慢些,因此須要耐心等待。雖然說遷移過程理應執行的很是快纔對,但當數據庫比較大、變化比較複雜時,遷移過程就須要耗費必定的時間了。爲了使用戶界面保持流暢,遷移過程必須在後臺線程裏執行。只有這樣作,用戶界面才能反映靈敏,並能把最新動態提供給用戶。實現數據遷移的難點在於如何防止用戶在遷移的過程當中操做應用程序。因爲此時數據還沒有準備好,因此咱們必須作這個限制,不然用戶就會對着黑屏幕不知所措。

未完成..

參考資料:

Core Data Model Versioning and Data Migration

自定義Core Data 遷移

Core Data 版本遷移經驗總結

相關文章
相關標籤/搜索