大家在学习和使用Core Data过程中,第一次进行版本号迁移的经历一定是记忆犹新,至少我是这种,XD。弄的不好,就会搞出一些因为迁移过程中数据模型出错导致的Crash。这里总结了一下Core Data版本号迁移过程中的经验。希望对大家实用。

写在前面

关于Core Data版本号迁移,这两篇文章都进行了分析,大家能够參考。

迁移准备

1) 选中project中的 xcdaramodeId 文件,Menu->Editor->Add Model Version

这一步加入完毕之后。project中的*xcdaramodeId* 文件将会被展开,而且出现了新添加的Model文件

2) 在Xcode右側的辅助工具栏中找到 Model Version, 选择刚刚加入的Model文件,这个时候你会发现Xcode文件夹中。Model文件上的绿色的勾选中了当前选择的Model文件

3) 在新的Model文件里改动最新的Entities等信息,记得也同一时候改动NSManagedObject Subclass相应的实现

4) 改动 NSPersistentStoreCoordinator 部分实现:

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) // 这里是加入的部分。名如其意,当我们须要自己主动版本号迁移时,我们须要在addPersistentStoreWithType方法中设置例如以下options
let options = [NSInferMappingModelAutomaticallyOption: true, NSMigratePersistentStoresAutomaticallyOption: true] var error: NSError? = nil
persistentStoreCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: options, error: &error)

轻量级迁移

当我们不过对数据模型添加实体或者可选属性时。上述步骤完毕后执行代码进行迁移是奏效的。这个过程文档中叫做 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 -&gt; RenamingID。设置Reanaming Identifier为之前相应的名称。

Mapping Models

假设我们对数据模型的改动不支持轻量级迁移,我们就须要像上文中所说的那样,自己创建Mapping Model。

打开创建好的 xcmappingmodel 文件,我们发现能够添加或者改动相应的 Entity Mappings, Attibute Mappings 和 Relationship Mappings。

Core Data提供了例如以下一组变量同意我们进行配置:

NSMigrationManagerKey: $manager

NSMigrationSourceObjectKey: $source

NSMigrationDestinationObjectKey: $destination

NSMigrationEntityMappingKey: $entityMapping

NSMigrationPropertyMappingKey: $propertyMapping

NSMigrationEntityPolicyKey: $entityPolicy

有时候,我们不只须要改动Entity的属性或者关系。能够使用NSEntityMigrationPolicy 自己定义整个迁移的过程。

继承NSEntityMigrationPolicy 实现迁移过程,然后选中相应的Entity
Mapping,在Xcode右側辅助工具栏中找到Custom Policy,并设置为实现迁移相应的类名。

NSEntityMigrationPolicy

NSEntityMigrationPolicy眼下提供了7个方法可供实现。它们的调用顺序例如以下:

1) 当迁移将要開始时,会调用

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

2) 在旧数据上构建新的实例时调用

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

结束时调用

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

3) 构建新的RelationShips调用

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

结束时调用

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

4) 验证,保存数据调用

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

5) 迁移结束时调用

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

迁移过程

这里分享的是自己项目中数据自己定义迁移的整个过程。并附上部分代码实现逻辑。

项目中採用的是渐进式迁移,渐进式迁移的概念在 自己定义 Core Data 迁移 一文中有介绍:

// 这段文字取自 <<自己定义 Core Data 迁移>> 一文

想像一下你刚刚部署一个包括版本号 3 的数据模型的更新。你的某个用户已经有一段时间没有更新你的应用了。这个用户还在版本号 1 的数据模型上。

那么如今你就须要一个从版本号 1 到版本号 3 的映射模型。同一时候你也须要版本号 2 到版本号 3 的映射模型。当你加入了版本号 4 的数据模型后。那你就须要创建三个新的映射模型。显然这样做的扩展性非常差,那就来试试渐进式迁移吧。

与其为每一个之前的数据模型到最新的模型间都建立映射模型,还不如在每两个连续的数据模型之间创建映射模型。

曾经面的样例来说,版本号 1 和版本号 2 之间须要一个映射模型。版本号 2 和版本号 3 之间须要一个映射模型。

这样就能够从版本号 1 迁移到版本号 2 再迁移到版本号 3。显然,使用这样的迁移的方式时,若用户在较老的版本号上迁移过程就会比較慢。但它能节省开发时间并保证健壮性,由于你仅仅须要确保从之前一个模型到新模型的迁移工作正常就可以,而更前面的映射模型都已经经过了測试。

1) 推断本地SQLite数据库文件是否存在,不存在直接退出整个迁移。

2) 检測当前本地数据库和数据模型是否一致。假设一致就退出迁移。

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

3) 取得当前数据库存储时用的数据模型,假设获取不到或者获取失败。退出迁移。

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

4) 取得当前project中全部数据模型相应的managedObjectModel用于迁移,假设获取的结果少于两个就退出迁移。

5) 从全部的managedObjectModel中遍历出终于使用的Model和当前数据库採用的Model之间的全部Model。依照version顺序构建一个新的 Model list,确保第一个是sourceModel,最后一个是当前须要使用的managedObjectModel。

6) 对生成的这个Model list进行循环,開始渐进式迁移。

7) 构建Model list中相邻两个Model之间的NSMappingModel实例,用做迁移。

 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一个
mappingModel = NSMappingModel.inferredMappingModelForSourceModel(modelA, destinationModel: modelB, error: nil) //假设终于取不到Mapping Model 就退出迁移
//假设得到了Mapping Model,就能够開始进行迁移
}

8) 最终能够開始进行迁移了,XD

9) 创建一个新的文件路径用来存储迁移过程中的数据文件

10) 使用上文中的 modelA 和 modelB 构建一个 NSMigrationManager 实例,使用

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

方法进行迁移,当中 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语句。

Core Data 版本号迁移经验总结的更多相关文章

  1. Core Data数据库迁移

    一. Lightweight Migration i. 适合场景 Simple addition of a new attribute Removal of an attribute A non-op ...

  2. Core Data 迁移与版本管理

    原文  http://chun.tips/blog/2014/11/28/core-data-ban-ben-qian-yi-jing-yan-zong-jie/ 主题 Core DataiOS开发 ...

  3. Core Data 版本数据迁移

    Core Data版本迁移基础 通常,在使用Core Data的iOS App上,不同版本上的数据模型变更引发的数据迁移都是由Core Data来负责完成的.这种数据迁移模式称为Lightweight ...

  4. 【转】深受开发者喜爱的10大Core Data工具和开源库

    http://www.cocoachina.com/ios/20150902/13304.html 在iOS和OSX应用程序中存储和查询数据,Core Data是一个很好的选择.它不仅可以减少内存使用 ...

  5. 手把手教你从Core Data迁移到Realm

    来源:一缕殇流化隐半边冰霜 (@halfrost ) 链接:http://www.jianshu.com/p/d79b2b1bfa72 前言 看了这篇文章的标题,也许有些人还不知道Realm是什么,那 ...

  6. 手把手教你从 Core Data 迁移到 Realm

    前言 看了这篇文章的标题,也许有些人还不知道Realm是什么,那么我先简单介绍一下这个新生的数据库.号称是用来替代SQLite 和 Core Data的.Realm有以下优点: 使用方便 Realm并 ...

  7. 3.3. 轻量级的迁移方式(Core Data 应用程序实践指南)

    持久化存储协调器会试着用新版的模板打开原来的持久化存储区,但是那是旧的模板,旧的格式,当然会出错.现在要做的就是迁移现有的持久化数据区,以便跟新模型匹配. 怎么进行迁移呢? 在什么时候进行迁移? 在向 ...

  8. 自定义 Core Data 迁移

    本文转载至 http://objccn.io/issue-4-7/ 感谢本文作者 朱宏旭 的不啬分享 自定义 Core Data 迁移似乎是一个不太起眼的话题.苹果在这方面只提供了很少的文档,若是初次 ...

  9. 《驾驭Core Data》 第一章 Core Data概述

    <驾驭Core Data>系列教程综合了<Core Data for iOS>,<Learning Core Data for iOS>,<Core Data ...

随机推荐

  1. 如果dom节点是动态添加进页面的,在页面节点绑定事件如何解决的问题。

    如果dom节点是动态添加进页面,想在节点绑定事件,传统的做法就是遍历节点,但会出现问题,也肯能有其他的办法,突然想到 可以依据事件冒泡,这样就不惧页面后添加节点而不响应事件的问题.比较结实.示例代码如 ...

  2. FNV哈希算法【转】

    转自:http://blog.csdn.net/hustfoxy/article/details/23687239 由来:FNV哈希算法全名为Fowler-Noll-Vo算法,是以三位发明人Glenn ...

  3. jmeter登录禅道案例

    下载jmeter,配置环境变量 变量名:JMETER_HOME 变量值:C:\Program Files\apache-jmeter-2.11 变量名:CLASSPATH 变量值:%JMETER_HO ...

  4. Linux 之 LNMP服务器搭建-前期准备

    LNMP服务器搭建-前期准备 参考教程:[千峰教育] 系统环境: 系统:centos 6.8. 软件安装位置: (1)软件源代码包存放位置:/lnmp/src 命令:mkdir -p /lnmp/sr ...

  5. linux下网络监控神器"iptraf-ng"

    优点:监控的网络信息很全面,安装和使用方便   #centos安装: #yum 源使用centos自带的base源即可. yum install -y iptraf-ng   #运行 iptraf-n ...

  6. (1)TensorFlow 概要

    TensorFlow:翻译成中文 张量流 计算图:又被称为有向图.数据流图 数据流图用结点和线的有向图来描述数学计算,节点一般用来表示施加的数学操作,也可以用来数据输入起点.输出终点,或者读取写入持久 ...

  7. Go语言入门——数组、切片和映射(下)

    上篇主要介绍了Go语言里面常见的复合数据类型的声明和初始化. 这篇主要针对数组.切片和映射这些复合数据类型从其他几个方面介绍比较下. 1.遍历 不管是数组.切片还是映射结构,都是一种集合类型,要从这些 ...

  8. Noip2016题解&总结

    原文放在我的uoj博客上,既然新开了blog,那就移过来了 玩具谜题(toy) 送分题.没有什么好说的. 直接按照题目的要求模拟即可. 标准的noip式day1T1. #include<cstd ...

  9. JD静态网页

    1.制作导航栏 ul>li*n>a 2.制作竖线 a.利用border b.利用  | c.利用矩形,宽度设为1,设置背景色,padding = 0 3.制作下三角 (1)◇ (2)两个盒 ...

  10. Java 浅析,生成OFD文件

    摘要:这几天遇到个需要,需要提供用户下载电子证照,最简单的方法实现:word做了一份模板,利用网页工具转成OFD文件,http://www.yozodcs.com/page/example.html用 ...