《Core Data应用开发实践指南》一3.5 通过迁移管理器来迁移数据

3.5 通过迁移管理器来迁移数据

除了通过NSPersistentStoreCoordinator来迁移存储区之外,还可以采用迁移管理器来做。迁移管理器可以使开发者全权掌控迁移过程中创建的文件,从而令他们能够按自己的方式来灵活处理迁移中的各种问题。使用迁移管理器的一个好处就是可以向用户报告迁移进度,使用户知道应用程序哪次会启动得比较慢一些,所以需要耐心等待。虽说迁移过程理应执行得非常快才对,但当数据库比较大、变动比较复杂时,迁移过程就需要耗费一定的时间了。为了使用户界面保持流畅,迁移过程必须在后台线程里执行。只有这样做,用户界面才能反应灵敏,并能把最新动态提供给用户。实现数据迁移的难点在于如何防止用户在迁移过程中操作应用程序。由于此时数据尚未准备好,所以我们必须做这个限制,否则用户就会对着黑屏不知所措。
请按下列步骤修改Grocery Dude,以便配置Migration 视图控制器(View Controller):
1. 选定Main.storyboard。
2. 向故事板(storyboard)中拖放一个新的View Controller,将它摆在现有的Navigation 控制器上方。
3. 向这个新的视图控制器中拖放Label与Progress View控件。
4. 把Progress View放在视图控制器正中,并将Label放在Progress View上方。
5. 按图3-10拓宽Label与Progress View控件,使其宽度与视图控制器相符。
6. 把Label的文本改为Migration Progress 0%,并将其居中(Centered),如图3-10左侧所示。
7. 把Progress View的进度(progress)设为0。
8. 选中视图控制器,然后在Identity Inspector界面(可以按“Option++3”组合键调出该界面)中把视图控制器的Storyboard ID设为migration。
9. 点击Editor>Resolve Auto Layout Issues>Reset to Suggested Constraints in View Controller菜单项。最终结果如图3-10所示。

由于Migration 视图控制器里的UILabel控件及UIProgressView控件需要在迁移过程中更新,所以我们需要一种能在代码中使用这两个控件的方式。为此,我们新建UIViewController的子类,并将其命名为MigrationVC。
请按下列步骤修改Grocery Dude,以便将MigrationVC类添加到新的组中:
1. 在现有的Grocery Dude 组上面右击鼠标,选择New Group。
2. 把新组的名字改为Grocery Dude View Controllers。
3. 选中Grocery Dude View Controllers 组。
4. 点击File>New>File...菜单项。
5. 新建iOS>Cocoa Touch>Objective-C class,并点击Next按钮。
6. 把Subclass of设为UIViewController,并把Class名称设为MigrationVC,然后点击Next按钮。
7. 确保Targets中的“Grocery Dude”处于勾选状态,然后点击Create,在Grocery Dude项目的文件夹中创建这个类。
8. 选中Main.storyboard。
9. 将Migration 视图控制器选中,在Identity Inspector界面(可按“Option++3”组合键调出该界面)里把Custom Class设为MigrationVC。该选项和刚才设置的Storyboard ID都位于同一界面中。
10. 点击View>Assistant Editor>Show Assistant Editor菜单项(或按“Option++Return”组合键),把Assistant Editor界面显示出来。
11. 此时Assistant Editor界面中应该就会自动显示出MigrationVC.h文件了。图3-11右上角是该界面的样貌。如果显示的不是这个文件,那可以先把migration 视图控制器选中,然后点击界面上方的Manual或Automatic,再选择MigrationVC.h。
12. 点击Control键并按住鼠标左键不放,从显示迁移进度的Label控件开始沿直线拖到MigrationVC.h代码的@end上方。松开鼠标左键之后,会弹出一个对话框,该对话框中列出了类型为UILabel的新特性,我们把该特性的Name设为label,并确保Storage是Strong,然后点击Connect。配置好的各选项如图3-11所示。
13. 按第12步所讲的操作方式,把Progress View(进度视图)同UIProgressView类型的特性链接起来,并将该特性命名为progressView。

为了向用户报告迁移进度,我们需要在CoreDataHelper.h文件中声明指向migration 视图控制器的指针。
请按下列步骤修改Grocery Dude,以添加新特性:
1. 点击View>Standard Editor>Show Standard Editor菜单项或按“+Return”组合键,把Standard Editor界面显示出来。
2. 把#import "MigrationVC.h"添加到CoreDataHelper.h文件顶部。
3. 在CoreDataHelper.h文件的现有特性下方添加@property(nonatomic, retain)MigrationVC*migrationVC;。
如果采用手动方式迁移数据,那就得在每次启动应用程序时判断数据是否需要迁移。为了做出该判断,我们需要知道存储区的URL,以便检查系统里是不是有这个存储区。如果有的话,那还要把存储区里的“模型元数据”(model metadata)与新的模型相比较,并根据比较的结果来判断新模型是否与现有的存储区相兼容。假如不兼容,那就要迁移数据了。把刚才说的这段逻辑写成代码,就得到了程序清单3-5中的isMigrationNecessary-ForStore方法。

请按下列步骤修改Grocery Dude,以便实现新的MIGRATION MANAGER 部分:
1. 将程序清单3-5中的代码添加到CoreDataHelper.m文件底部,并将其放在@end语句之前。
假如已经确定要迁移数据,那么接下来就该执行迁移了。此过程分为三步,程序清单3-6中的注释写明了这三个步骤。


STEP 1(第一步) 用于收集执行数据迁移所需的信息,这些信息分别是:
源模型,也就是通过NSPersistentStoreCoordinator的metadataFor-PersistentStoreOfType方法从持久化存储区里获取到的元数据。
目标模型,也就是_model实例变量。
映射模型,该模型由系统自动决定,开发者只需把nil当做mappingModelFrom-Bundles:forSourceModel:destinationModel:方法的第一个参数,并把源模型和目标模型也一并传过去即可。
STEP 2(第二步) 就是实际的迁移过程。我们先用源模型与目标模型创建NSMigra-tionManager实例,然后在调用migrateStoreFromURL之前,还需把目标存储区准备好。该目标存储区只是个为迁移而设的临时存储区。
STEP 3(第三步) 只有在顺利完成迁移时才会触发。replaceStore方法用于在迁移完成后清理旧的存储区。执行完第二步之后,目标位置上就会出现一份新的存储区了,但是,我们还必须把这个迁移过来的新存储区放回到原来的位置上,并且要把它的文件名起得和旧存储区一样,唯有如此,Core Data才能使用这个新存储区。为了使用新迁移好的存储区,我们需要把旧存储区删掉,并将新存储区放到旧存储区的位置上。当开发自己的项目时,也可以在删除旧存储区之前先把它备份到某处。是否需要备份,由你自己决定,如果真要备份,那可能得稍微修改一下replaceStore方法。备份旧存储区会导致应用程序在迁移过程中对存储量的需求翻倍。
当迁移进度有变化时,系统会调用observeValueForKeyPath方法,而我们可以通过该方法把目前的迁移进度告知用户。migrationManager的migrationProgress特性一旦改变,我们就可通过该方法来更新migrationVC。
程序清单3-7列出了observeValueForKeyPath及replaceStore方法的代码。

请按下列步骤修改Grocery Dude,以继续实现MIGRATION MANAGER 部分:
1. 把程序清单3-7里的代码添加到CoreDataHelper.m文件MIGRATION MANAGER部分的底部,并放在@end上方,然后按同样方式把程序清单3-6里的代码也加进去。
为了在后台通过migrationManager来迁移数据,我们需要使用程序清单3-8中的方法。

performBackgroundManagedMigrationForStore方法用故事板标识符来实例化视图控制器,并把它展示给用户。用户的操作由这个视图来接受,而我们则可以开始迁移数据了。migrateStore方法会在后台线程中执行。等迁移完数据,我们就可像平常那样通过_coordinator来添加存储区,并把显示迁移进度所用的view关闭,然后,应用程序就可以照常往下运行了。
请按下列步骤修改Grocery Dude,以继续实现MIGRATION MANAGER部分:
1. 把程序清单3-8里的代码添加到CoreDataHelper.m文件MIGRATION MANAGER 部分的底部,并放在@end语句上方。
检测是否需要执行数据迁移的最佳时机应该是在把存储区添加到_coordinator前的那一刻。为了安排好这项检测,我们需要修改CoreDataHelper.m文件中的loadStore方法。如果真的要迁移,那么迁移操作就会在此刻触发。相关代码如程序清单3-9所示。

请按下列步骤修改Grocery Dude,以完成本节范例:
1. 修改CoreDataHelper.m文件中的loadStore方法,用程序清单3-9里的代码把原有代码替换掉。
2. 基于Model 3,添加名为Model 4的模型版本。
3. 选定Model 4.xcdatamodel。
4. 删除Amount实体。
5. 新增名为Unit的实体,并添加名为name的字符串类型属性。
6. 根据Unit实体来创建NSManagedObject子类。在保存类文件的这一步里,别忘了勾选Targets中的“Grocery Dude”。
7. 将Model 4设为当前模型。
8. 以Model 3为源模型,以Model 4为目标模型,新建映射模型。在保存映射模型文件的这一步里,别忘了勾选Targets中的“Grocery Dude”,然后,把这个模型存为Model3toModel4。
9. 选定Model3toModel4.xcmappingmodel。
10. 选定ENTITIES MAPPINGS中的Unit。
11. 将Unit实体的Source设为Amount,并给名为name的Destination 属性设定Value Expression,将这个Value Expression写成$source.xyz。此时ENTITIES MAPPINGS中的Unit实体应该会自动改名为AmountToUnit,如图3-12所示。

现在基本上已经可以开始执行迁移了,不过demo方法里的获取请求仍然在使用旧的Amount实体。
请按下列步骤修改Grocery Dude,使demo方法不再获取Amount实体,而是改为获取Unit实体:
1. 把AppDelegate.m文件顶部的#import "Amount.h"替换成#import "Unit.h"。
2.修改AppDelegate.m文件的demo方法,用程序清单3-10中的代码替换原有代码。新的代码只从持久化存储区里获取50个Unit对象。

迁移管理器终于实现好了!运行应用程序,仔细观察设备屏幕!你眼前会出现Migration Progress界面,它会显示数据的迁移进度。同时,这个进度也会出现在控制台里。
请用第2章讲过的办法来查看Grocery-Dude.sqlite文件中ZUNIT表的内容。正常的结果如图3-14所示。假如你已把默认的日志记录模式关闭,但Stores目录里却还有-wal文件,那么请点击Product>Clean菜单项并重新运行应用程序,然后再次查看sqlite文件。

操作结果要是和图3-14一样的话,那你真的太棒了,因为你已把三种模型迁移方式全部实现出来了!本书接下来的内容要使用轻量级迁移方式,所以现在必须重新启用它。
请按下列步骤修改Grocery Dude,以重新启用轻量级迁移方式:
1. 修改CoreDataHelper.m文件的loadStore方法,把NSInferMappingModel-AutomaticallyOption选项改为@YES。
2. 修改CoreDataHelper.m文件的loadStore方法,把useMigrationManager设为NO。
3. 删除AppDelegate.m文件demo方法中的所有代码。
旧的映射模型以及根据旧实体所创建出来的NSManagedObject子类现在都已经没有用处了。虽说也可以把它们删掉,但为了便于日后查阅,我们还是将其留在项目之中吧。

时间: 2024-09-30 04:49:55

《Core Data应用开发实践指南》一3.5 通过迁移管理器来迁移数据的相关文章

《Core Data应用开发实践指南》一第3章 托管对象模型的迁移

第3章 托管对象模型的迁移 不创新者永不犯错.-阿尔伯特•爱因斯坦第2章介绍了托管对象模型的基础知识,但我们把内容局限在了一个实体及几个属性上面.按理说接下来就该向模型里面添加更多的内容了,但在执行修改之前,还必须完成一些准备步骤,以防应用程序因为这些改动而崩溃.本章就来介绍如何添加模型版本及模型映射,同时也会演示几种不同的迁移技术,供你在升级模型时选用.

《Core Data应用开发实践指南》一3.7 习题

3.7 习题 请在所学内容的基础之上完成下列试验: 把当前模型版本设为Model 3,并运行应用程序.这次系统应该不会崩溃,因为它会自动推断数据的降级过程.请注意:系统之所以会自动推断,是因为我们刚才把NSInfer-MappingModelAutomaticallyOption重新启用了.但是在实际的程序开发中,为了把属性之间的映射关系处理好,需要配置名为Model4toModel3的映射模型. 查看Grocery-Dude.sqlite文件中的ZAMOUNT表,你会发现一个严重的问题:原来的

《Core Data应用开发实践指南》一1.2 Core Data的适用场合

1.2 Core Data的适用场合 如果应用程序要保存的设置数据太多,以致NSUserDefaults及"特性列表"(property list)这种简单的存储方案无法应付,那么就会出现内存占用量方面的问题.解决办法是直接使用数据库或通过Core Data来间接操作数据库.选用Core Data的好处是,不用再花时间编写数据库接口的代码了.此外,你还将享受性能方面的优势,而且可以使用诸如撤销及验证等强大的功能.假如选择直接使用数据库,那就要花时间去做开发与测试工作,也就是通常所说的&

《Core Data应用开发实践指南》一3.1 修改托管对象模型

3.1 修改托管对象模型 在应用程序的进化过程中,其托管对象模型也可能需要改变.对于一些比较简单的修改,诸如设定属性的默认值.设定验证规则.使用获取请求模板等,是可以直接实施的.而对于另外一些更为结构化的(structural)修改,则需先把持久化存储区迁移到新的模型版本才行.假如没有提供迁移数据所需的映射与设定,那么应用程序就会崩溃.为了继续构建范例程序,需要把上一章中的代码添加到Grocery Dude项目中.或者可以去http://www.timroadley.com/LearningCo

《Core Data应用开发实践指南》一2.2 添加托管对象模型

2.2 添加托管对象模型 在第1章中,我们通过CoreDataHelper.m文件里的mergedModelFromBundles方法初始化了托管对象模型.然而现在的问题是:项目里根本就没有模型可用!如果连模型都没有的话,那Core Data就彻底失去意义了,所以,我们这个时候应该创建模型文件.模型文件一般会含有"对象图",而对象图则用来表示应用程序的数据结构以及其他一些可以简化应用程序开发的东西,我们稍后再来解释.请按下列步骤修改Grocery Dude,以便添加数据模型文件: 在现

《Core Data应用开发实践指南》一第1章 初次尝试Core Data应用程序

第1章 初次尝试Core Data应用程序 如果不能把一件事用简单的话说清楚,那就表明你理解得还不够透彻.-阿尔伯特•爱因斯坦"体验式学习"(kinesthetic learning)或者说"从实践中学习"(learning by doing),是接收并记住信息的绝佳手段.即便对于许多有经验的程序员来说,Core Data也是个相当棘手的话题,于是,笔者就适时地编写了你手中的这本书,它以实践的方式来讲解Core Data.本书不会过早地讲解一些比较难懂的话题,本章只

《Core Data应用开发实践指南》一1.3 创建Grocery Dude项目

1.3 创建Grocery Dude项目 Grocery Dude是个运行在iPhone上的范例程序,在学习本书的过程中,你将了解到它的制作流程.学会了Core Data中的某个特性或某项开发技巧之后,你可以将其运用在Grocery Dude程序上面.到了本书收尾的时候,你将会制作好一款功能完备而且运行速度很快的Code Data程序,它能够同iCloud紧密地集成在一起.假如你现在就想直接看看成品,那可以去App Store下载Grocery Dude.请注意,Grocery Dude是专门为

《Core Data应用开发实践指南》一3.3 轻量级的迁移方式

3.3 轻量级的迁移方式 把新模型设为当前版本之后,必须迁移现有的持久化存储区,只有这样,才能正常使用新模型.这是因为,持久化存储区协调器会试着用新版的模型来打开原有的存储区,但由于原有的存储区是用旧版模型创建的,所以该操作会失败.在向NSPersis-tentStoreCoordinator添加存储区的时候,只需将下列选项放在NSDictionary里传过去,即可自动完成存储区的迁移工作:如果传给NSPersistentStoreCoordinator的NSMigratePersistentS

《Core Data应用开发实践指南》一1.4 为现有的应用程序添加Core Data支持

1.4 为现有的应用程序添加Core Data支持 在Xcode中创建iOS应用程序项目时,可以使用各种起始模板(starting-point template).假如要根据Master-Detail.Utility Application或Empty Application等模板来创建项目,那么只需勾选Use Core Data,即可在项目中使用Core Data.不过,Grocery Dude项目是根据Single View Application模板创建的,它起初并没有包含Core Dat