在应用程序的进行过程当中,其托管对象模型也可能须要进行修改。对于一些比较简单的修改,诸如设定属性的默认值、设定验证规则、使用获取请求模板等,是能够直接实施的。而对于另一些更为结构化的修改,则须要把持久化存储区迁移到新的模型版本才行。假如没有提供迁移数据所须要的映射与设定,那么应用程序就会崩溃。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.如图:版本控制
若是想正常运行应用程序,那么咱们还须要配置好迁移选项,告诉Core Data应该如何去迁移。要是如今就去运行应用程序的话,那天然仍是会发生Store is incompatible(存储区不兼容)错误。
把新的模型设置为当前版本以后,必须迁移现有的持久化存储区,只有这样,才能正常使用新模型。这是由于,持久化存储区协调器会试着使用新的模型来打开原有的存储区,可是原有的存储区是用旧版本的模型建立的,因此会出现错误。在向NSPersistentStoreCoordinator添加存储区的时候,只须要将下列选项放在NSDictionary里面传过去,便可自动完成存储区的迁移工做:
若是传给NSPersistentStoreCoordinator的NSMigratePersistenStoresAutomaticallyOption是YES,那么Core Data 就会试着把低版本的持久化存储区迁移到最新版本的模型。
若是传给NSPersistentStoreCoordinator的NSInferMappingModelAutomaticallyOption是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
,以添加新的映射模型:
确保Data Model 处于选中状态
点击 File > New > File ... 菜单项
选择 iOS > Core Data > Mapping Model , 并点击Next 按钮
把 Model2.xcdatamodel 选为Source Data Model ,并点击Next按钮
把 Model3.xcdatamodel 选为Target Data Model ,并点击Next按钮
将mapping model 的名称设为Model2toModel3 ,并将其保存
选中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
来迁移存储区以外,还能够经过采用迁移管理器来作。迁移管理器可使开发者全权掌握迁移过程当中建立的文件,从而令他们可以按本身的方式来灵活处理迁移中的种种问题。使用迁移管理器的一个好处就是能够向用户报告迁移进度,使用户知道应用程序哪次会启动的比较慢些,因此须要耐心等待。虽然说迁移过程理应执行的很是快才对,但当数据库比较大、变化比较复杂时,迁移过程就须要耗费必定的时间了。为了使用户界面保持流畅,迁移过程必须在后台线程里执行。只有这样作,用户界面才能反映灵敏,并能把最新动态提供给用户。实现数据迁移的难点在于如何防止用户在迁移的过程当中操做应用程序。因为此时数据还没有准备好,因此咱们必须作这个限制,不然用户就会对着黑屏幕不知所措。
未完成..