日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Core Data 迁移与版本管理

發(fā)布時(shí)間:2025/7/25 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Core Data 迁移与版本管理 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
原文??http://chun.tips/blog/2014/11/28/core-data-ban-ben-qian-yi-jing-yan-zong-jie/ 主題?Core Data?iOS開(kāi)發(fā)

大家在學(xué)習(xí)和使用Core Data過(guò)程中,第一次進(jìn)行版本遷移的經(jīng)歷一定是記憶猶新,至少我是這樣的,XD。弄的不好,就會(huì)搞出一些由于遷移過(guò)程中數(shù)據(jù)模型出錯(cuò)導(dǎo)致的Crash。這里總結(jié)了一下Core Data版本遷移過(guò)程中的經(jīng)驗(yàn),希望對(duì)大家有用。

寫(xiě)在前面

關(guān)于Core Data版本遷移,這兩篇文章都進(jìn)行了分析,大家可以參考。

  • Core Data Model Versioning and Data Migration Programming Guide
  • 自定義 Core Data 遷移

遷移準(zhǔn)備

1) 選中工程中的?xcdaramodeId?文件,Menu->Editor->Add Model Version?

這一步添加完成之后,工程中的*xcdaramodeId* 文件將會(huì)被展開(kāi),并且出現(xiàn)了新增加的Model文件

2) 在Xcode右側(cè)的輔助工具欄中找到 Model Version, 選擇剛剛添加的Model文件,這個(gè)時(shí)候你會(huì)發(fā)現(xiàn)Xcode目錄中,Model文件上的綠色的勾選中了當(dāng)前選擇的Model文件

3) 在新的Model文件中修改最新的Entities等信息,記得也同時(shí)修改NSManagedObject Subclass對(duì)應(yīng)的實(shí)現(xiàn)

4) 修改?NSPersistentStoreCoordinator?部分實(shí)現(xiàn):?

let modelFilename = "the model file name in your project" let modelPath = NSBundle.mainBundle().pathForResource(modelFIlename, ofType: "momd")let managedObjectModel = NSManagedObjectModel(contentsOfURL: NSURL.fileURLWithPath(modelPath) let persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel) // 這里是添加的部分,名如其意,當(dāng)我們需要自動(dòng)版本遷移時(shí),我們需要在addPersistentStoreWithType方法中設(shè)置如下options let options = [NSInferMappingModelAutomaticallyOption: true, NSMigratePersistentStoresAutomaticallyOption: true] var error: NSError? = nil persistentStoreCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: options, error: &error)

輕量級(jí)遷移

當(dāng)我們僅僅是對(duì)數(shù)據(jù)模型增加實(shí)體或者可選屬性時(shí),上述步驟完成后運(yùn)行代碼進(jìn)行遷移是奏效的。這個(gè)過(guò)程文檔中叫做?Lightweight Migration?,當(dāng)我們進(jìn)行輕量級(jí)遷移時(shí),?NSPersistentStoreCoordinator?會(huì)為我們自動(dòng)推斷出一個(gè)?Mapping Model?。如果有更加復(fù)雜的改變,我們就需要自己去實(shí)現(xiàn)Mapping Mode。?

添加Mapping Model過(guò)程: New File->CoreData->Mapping Model, 選擇我們需要進(jìn)行Mapping的兩個(gè)Model,最終會(huì)生成一個(gè) *xcmappingmodel* 文件,大家可以打開(kāi)文件,看到里面生成了Model之間的映射。

官方文檔中介紹如下的改變支持輕量級(jí)遷移:

  • 為Entity簡(jiǎn)單的添加一個(gè)屬性
  • 為Entity移除一個(gè)屬性
  • 屬性值由 Optional<-> Non-optional 之間轉(zhuǎn)換
  • 為屬性設(shè)置 Default Value
  • 重命名Entity或者Attribute
  • 增加一個(gè)新的relationship 或者刪除一個(gè)已經(jīng)存在的 relationship
  • 重命名relationship
  • 改變r(jià)elationship to-one<-> to-many 等
  • 增加,刪除Entities
  • 增加新的 Parent 或者 Child Entity
  • 從Hierarchy中移除Entities

輕量級(jí)遷移不支持合并Entity的層級(jí):比如在舊的Model中兩個(gè)已知的Entities沒(méi)有共享一個(gè)共同的Parent Entity,那么在新的Model中它們也不能夠共享一個(gè)共同的Parent Entity。

在為屬性或者Entity等重命名時(shí),我們需要在Xcode右側(cè)輔助工具欄中找到 Versioning -&gt; RenamingID,設(shè)置Reanaming Identifier為之前對(duì)應(yīng)的名稱。

Mapping Models

如果我們對(duì)數(shù)據(jù)模型的修改不支持輕量級(jí)遷移,我們就需要像上文中所說(shuō)的那樣,自己創(chuàng)建Mapping Model。

打開(kāi)創(chuàng)建好的?xcmappingmodel?文件,我們發(fā)現(xiàn)可以增加或者修改對(duì)應(yīng)的 Entity Mappings, Attibute Mappings 和 Relationship Mappings。?

Core Data提供了如下一組變量允許我們進(jìn)行配置:

NSMigrationManagerKey: $managerNSMigrationSourceObjectKey: $source NSMigrationDestinationObjectKey: $destination NSMigrationEntityMappingKey: $entityMapping NSMigrationPropertyMappingKey: $propertyMapping NSMigrationEntityPolicyKey: $entityPolicy

有時(shí)候,我們不僅僅需要修改Entity的屬性或者關(guān)系,可以使用?NSEntityMigrationPolicy?自定義整個(gè)遷移的過(guò)程。繼承?NSEntityMigrationPolicy?實(shí)現(xiàn)遷移過(guò)程,然后選中對(duì)應(yīng)的Entity Mapping,在Xcode右側(cè)輔助工具欄中找到Custom Policy,并設(shè)置為實(shí)現(xiàn)遷移對(duì)應(yīng)的類名。?

NSEntityMigrationPolicy

NSEntityMigrationPolicy目前提供了7個(gè)方法可供實(shí)現(xiàn),它們的調(diào)用順序如下:

1) 當(dāng)遷移將要開(kāi)始時(shí),會(huì)調(diào)用

func beginEntityMapping(mapping: NSEntityMapping, manager: NSMigrationManager, error: NSErrorPointer) -> Bool

2) 在舊數(shù)據(jù)上構(gòu)建新的實(shí)例時(shí)調(diào)用

func createDestinationInstancesForSourceInstance(sInstance: NSManagedObject, entityMapping mapping: NSEntityMapping, manager: NSMigrationManager, error: NSErrorPointer) -> Bool

結(jié)束時(shí)調(diào)用

func endInstanceCreationForEntityMapping(mapping: NSEntityMapping, manager: NSMigrationManager, error: NSErrorPointer) -> Bool

3) 構(gòu)建新的RelationShips調(diào)用

func createRelationshipsForDestinationInstance(dInstance: NSManagedObject, entityMapping mapping: NSEntityMapping, manager: NSMigrationManager, error: NSErrorPointer) -> Bool`

結(jié)束時(shí)調(diào)用

func endRelationshipCreationForEntityMapping(mapping: NSEntityMapping, manager: NSMigrationManager, error: NSErrorPointer) -> Bool

4) 驗(yàn)證,保存數(shù)據(jù)調(diào)用

func performCustomValidationForEntityMapping(mapping: NSEntityMapping, manager: NSMigrationManager, error: NSErrorPointer) -> Bool

5) 遷移結(jié)束時(shí)調(diào)用

func endEntityMapping(mapping: NSEntityMapping, manager: NSMigrationManager, error: NSErrorPointer) -> Bool

遷移過(guò)程

這里分享的是自己項(xiàng)目中數(shù)據(jù)自定義遷移的整個(gè)過(guò)程,并附上部分代碼實(shí)現(xiàn)邏輯。項(xiàng)目中采用的是漸進(jìn)式遷移,漸進(jìn)式遷移的概念在?自定義 Core Data 遷移?一文中有介紹:?

// 這段文字取自 <<自定義 Core Data 遷移>> 一文想像一下你剛剛部署一個(gè)包含版本 3 的數(shù)據(jù)模型的更新。你的某個(gè)用戶已經(jīng)有一段時(shí)間沒(méi)有更新你的應(yīng)用了,這個(gè)用戶還在版本 1 的數(shù)據(jù)模型上。那么現(xiàn)在你就需要一個(gè)從版本 1 到版本 3 的映射模型。同時(shí)你也需要版本 2 到版本 3 的映射模型。當(dāng)你添加了版本 4 的數(shù)據(jù)模型后,那你就需要?jiǎng)?chuàng)建三個(gè)新的映射模型。顯然這樣做的擴(kuò)展性很差,那就來(lái)試試漸進(jìn)式遷移吧。與其為每個(gè)之前的數(shù)據(jù)模型到最新的模型間都建立映射模型,還不如在每?jī)蓚€(gè)連續(xù)的數(shù)據(jù)模型之間創(chuàng)建映射模型。以前面的例子來(lái)說(shuō),版本 1 和版本 2 之間需要一個(gè)映射模型,版本 2 和版本 3 之間需要一個(gè)映射模型。這樣就可以從版本 1 遷移到版本 2 再遷移到版本 3。顯然,使用這種遷移的方式時(shí),若用戶在較老的版本上遷移過(guò)程就會(huì)比較慢,但它能節(jié)省開(kāi)發(fā)時(shí)間并保證健壯性,因?yàn)槟阒恍枰_保從之前一個(gè)模型到新模型的遷移工作正常即可,而更前面的映射模型都已經(jīng)經(jīng)過(guò)了測(cè)試。

1) 判斷本地SQLite數(shù)據(jù)庫(kù)文件是否存在,不存在直接退出整個(gè)遷移。

2) 檢測(cè)當(dāng)前本地?cái)?shù)據(jù)庫(kù)和數(shù)據(jù)模型是否一致,如果一致就退出遷移。

let storeURL = NSURL(fileURLWithPath: "SQLite file path") let managedObjectModel: NSManagedObjectModel = Your current managed object modellet sourceMetadata = NSPersistentStoreCoordinator.metadataForPersistentStoreOfType(NSSQLiteStoreType, URL:storeURL!, error: nil) Bool needMigration = managedObjectModel.isConfiguration(nil, compatibleWithStoreMetadata: sourceMetadata)

3) 取得當(dāng)前數(shù)據(jù)庫(kù)存儲(chǔ)時(shí)用的數(shù)據(jù)模型,如果獲取不到或者獲取失敗,退出遷移。

if let sourceModel = NSManagedObjectModel.mergedModelFromBundles(nil, forStoreMetadata: sourceMetadata!) {println("\(sourceModel)") } else {return }

4) 取得當(dāng)前工程中所有數(shù)據(jù)模型對(duì)應(yīng)的managedObjectModel用于遷移,如果獲取的結(jié)果少于兩個(gè)就退出遷移。

5) 從所有的managedObjectModel中遍歷出最終使用的Model和當(dāng)前數(shù)據(jù)庫(kù)采用的Model之間的所有Model,按照version順序構(gòu)建一個(gè)新的 Model list,確保第一個(gè)是sourceModel,最后一個(gè)是當(dāng)前需要使用的managedObjectModel。

6) 對(duì)生成的這個(gè)Model list進(jìn)行循環(huán),開(kāi)始漸進(jìn)式遷移。

7) 構(gòu)建Model list中相鄰兩個(gè)Model之間的NSMappingModel實(shí)例,用做遷移。

for var index = 0; index < modelList.count - 1; index++ { let modelA = modelList[index] let modelB = modelList[index + 1] //檢查是否有自定義的Mapping model存在 var mappingModel : NSMappingModel? = NSMappingModel(fromBundles: nil, forSourceModel: modelA, destinationModel: modelB) //如果不存在,嘗試infer一個(gè) mappingModel = NSMappingModel.inferredMappingModelForSourceModel(modelA, destinationModel: modelB, error: nil) //如果最終取不到Mapping Model 就退出遷移 //如果得到了Mapping Model,就可以開(kāi)始進(jìn)行遷移 }

8) 終于可以開(kāi)始進(jìn)行遷移了,XD

9) 創(chuàng)建一個(gè)新的文件路徑用來(lái)存儲(chǔ)遷移過(guò)程中的數(shù)據(jù)文件

10) 使用上文中的 modelA 和 modelB 構(gòu)建一個(gè)?NSMigrationManager?實(shí)例,使用?

func migrateStoreFromURL(sourceURL: NSURL, type sStoreType: String, options sOptions: [NSObject : AnyObject]?, withMappingModel mappings: NSMappingModel?, toDestinationURL dURL: NSURL, destinationType dStoreType: String, destinationOptions dOptions: [NSObject : AnyObject]?, error: NSErrorPointer) -> Bool

方法進(jìn)行遷移,其中?toDestinationURL?參數(shù)是我們?cè)诓襟E9中創(chuàng)建的路徑。如果migrate失敗,就退出整個(gè)遷移過(guò)程。?

11) 數(shù)據(jù)替換 1.把原始的source文件移動(dòng)到新的backup文件夾中 2.使用步驟9中文件下生成的遷移之后的數(shù)據(jù)文件移動(dòng)到原始的數(shù)據(jù)的路徑下 3.刪除backup

12) 回到步驟7,進(jìn)行下一次迭代遷移,直到結(jié)束

遷移調(diào)試

我們可以在Xcode中設(shè)置啟動(dòng)參數(shù)?-com.apple.coredata.ubiquity.logLevel 3?或者?-com.apple.CoreData.SQLDebug 1?, 這樣在程序運(yùn)行時(shí),控制臺(tái)將會(huì)打印更多Core Data使用中的信息,包括調(diào)用的SQL語(yǔ)句。?

轉(zhuǎn)載于:https://www.cnblogs.com/lihaibo-Leao/p/5536930.html

總結(jié)

以上是生活随笔為你收集整理的Core Data 迁移与版本管理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。