Core Data版本迁移基础

通常,在使用Core Data的iOS App上,不同版本上的数据模型变更引发的数据迁移都是由Core Data来负责完成的。
这种数据迁移模式称为Lightweight Migration(可能对于开发人员来说是lightweight),开发人员只要在添加Persistent Store时设置好对应选项,其它的就交付给Core Data来做了:

从命名上可以看出这两个选项分别代表:自动迁移Persistent Store,以及自动创建Mapping Model。

自动迁移Persistent Store很好理解,就是将数据从一个物理文件迁移到另一个物理文件,通常是因为物理文件结构发生了变化。
自动创建Mapping Model是为迁移Persistent Store服务的,所以当自动迁移Persistent Store选项NSMigratePersistentStoreAutomaticallyOption为@(YES)、且找不到Mapping Model时,coordinator会尝试创建一份。
其它初始化场景可以参考Initiating the Migration Process。

既然是尝试创建,便有成功和失败的不同结果。只有当数据模型的变更属于某些基本变化时,才能够成功地自动创建出一份Mapping Model,比如:新增一个字段;删除一个字段;必填字段转换成可选字段;可选字段转换成必填字段,同时提供了默认值等等。

因为可能创建Mapping Model失败,所以考虑容错性的话,可以事先判断下能否成功推断出一份Mapping Model:

利用如上类方法,如果无法创建一份Mapping Model,则会返回nil,并带有具体原因。

以上都建立在Core Data能够自动找到sourceModel和destinationModel的基础上,如果无法找到对应的两份Model,则需要开发人员手工创建NSMigrationManager来进行数据迁移(可以参考Use a Migration Manager if Models Cannot Be Found Automatically)。

版本迁移过程

那么,数据迁移的过程是如何进行的?

首先,发生数据迁移需要三个基本条件:可以打开既有persistent store的sourceModel,新的数据模型destinationModel,以及这两者之间的映射关系Mapping Model。

利用这三样,当调用如下代码时(addPersistentStore):

Core Data创建了两个stack(分别为source stack和destination stack,可以参考Core Data stack),然后遍历Mapping Model里每个entity的映射关系,做以下三件事情:
     1. 基于source stack,Core Data先获取现有数据,然后在destination stack里创建当前entity的实例,只填充属性,不建立关系;
     2. 重新创建entity之间的关系;
     3. 验证数据的完整性和一致性,然后保存。

考虑到第二步是重新建立entity之间的关系,那么应该是在第一步就把所有entity的对象都创建好了,并且保留在内存中,为第二步服务(事实上也是如此)。

完成第二步后,所有数据还是维持在内存中(可能还有两份,因为有两个stack),在完成数据验证后才真正保存。

这样的话,会容易导致内存占用过多,因为Core Data在这个迁移过程中也没有一种机制清理响应的context。所以在数据量较多时,App可能会遇到在数据迁移过程因为内存紧张而被系统干掉。
针对这种情况,我们可以自定义迁移过程。

自定义数据迁移(解决内存问题)

自定义数据迁移的过程通畅分为三步:
第一步是判断是否需要进行数据迁移:

第二步是创建一个Migration Manager对象:

第三步是真正发生数据迁移:

上面三幅图所展示的代码在内存使用量上跟lightweight migration也没什么区别,无法解决内存峰值过高的问题。

虽然Core Data专家Marcus S. Zarra比较倾向坚持使用lightweight migration,不过对于上述内存占用过多的问题,Apple官方推荐使用Multiple Passes来解决。

关于Multiple Passes,官方文档的说明很简明扼要,如有需要,可以参考Stackoverflow上的这么一篇帖子。

用我的话往简单里说就是对数据模型进行划分,把一份Mapping Model拆分成多份,然后分成多次迁移,从而降低内存峰值。这需要对数据库进行全盘的考虑(甚至可能需要变更部分设计),然后通过合理的划分把相关联的Entity放在一份Mapping Model里面(因为要建立关联)。

新的问题

采用上述方案来解决数据迁移过程中内存峰值的问题,我们仍然需要关注迁移所耗费的时间、内存,从而能够在数据上验证方案的有效性,并且在用户交互方面进行一些必要的更改(总不能让用户傻傻地在那边等数据迁移吧)。

虽然可以解决内存峰值的问题,但也引进了其它问题。

1. 需要对数据模型进行划分(以及变更),存在一定的工作量和风险;
2. 需要手工建立多份Mapping Model;
3. 需要手工编写Multiple Passes迁移代码;
4. 需要在每个版本变迁中都再次创建新的Mapping Model,且在跨版本迁移过程存在着其它问题;
5. 数据模型版本多起来,就面临着跨版本迁移的问题,是要为每个历史版本创建到最新模型的Mapping Model,还是只维护最近两个版本的Mapping Model(更早的版本通过相邻版本的Mapping Model依次迁移过来,比较耗时)?
6. 对数据模型重新划分后,无关的Entity简单变更也会引起整个store和model的不兼容,需要迁移,那么是否考虑分库?
7. 这么大的动作服务的用户数是很少的(只有少数用户会遇到,或者是很少),但却是比较资深的(因为消息记录多),疼。。。
8. 这无法解决单个Entity数据量过大的问题,针对这种场景,只能自己手工编码进行小批量的数据迁移;

Core Data 版本数据迁移的更多相关文章

  1. iOS开发——数据持久化Swift篇&使用Core Data进行数据持久化存储

    使用Core Data进行数据持久化存储   一,Core Data介绍 1,Core Data是iOS5之后才出现的一个数据持久化存储框架,它提供了对象-关系映射(ORM)的功能,即能够将对象转化成 ...

  2. Core Data存储数据出错(This NSPersistentStoreCoordinator has no persistent stores (unknown))

    Core Data存储数据的时候崩溃,崩溃信息: reason: 'This NSPersistentStoreCoordinator has no persistent stores (unknow ...

  3. HBase跨版本数据迁移总结

    某客户大数据测试场景为:Solr类似画像的数据查出用户标签--通过这些标签在HBase查询详细信息.以上测试功能以及性能. 其中HBase的数据量为500G,Solr约5T.数据均需要从对方的集群人工 ...

  4. Entity Framework Core中的数据迁移命令

    使用程序包管理控制台输入命令. 数据迁移命令: Add-Migration  对比当前数据库和模型的差异,生成相应的代码,使数据库和模型匹配的. Remove-Migration 删除上次的迁移 Sc ...

  5. Swift - 使用Core Data进行数据持久化存储

    一,Core Data介绍 1,Core Data是iOS5之后才出现的一个数据持久化存储框架,它提供了对象-关系映射(ORM)的功能,即能够将对象转化成数据,也能够将保存在数据库中的数据还原成对象. ...

  6. ASP.NET Core ef启用数据迁移

    创建一个项目 通过Nuget获取EF Core相关的扩展包 appsettings.json 建立数据库连接串 创建数据库上下文EntityDbContext类,用于实体类映射数据库表 使用包管理器控 ...

  7. Core Data 迁移与版本管理

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

  8. iOS开发中的4种数据持久化方式【二、数据库 SQLite3、Core Data 的运用】

                   在上文,我们介绍了ios开发中的其中2种数据持久化方式:属性列表.归档解档.本节将继续介绍另外2种iOS持久化数据的方法:数据库 SQLite3.Core Data 的运 ...

  9. iphone数据存储之-- Core Data的使用(一)

    http://www.cnblogs.com/xiaodao/archive/2012/10/08/2715477.html 一.概念 1.Core Data 是数据持久化存储的最佳方式 2.数据最终 ...

随机推荐

  1. nginx的rewrite,gzip,反向代理学习笔记

    rewrite模块名:ngx_http_rewrite_module默认自动被编译 指令:rewrite regex replacement [flag] regex :正则表达式,用于匹配用户请求的 ...

  2. 在PyQt中直接使用ui文件并加载qrc资源文件

    1. 用Qt设计师创建一个包含qrc资源文件的ui文件 2.打开cmd使用以下命令把qrc资源文件转换成十六进制的py文件 pyrcc4 -o C:\res.py C:\res.qrc pyrcc4 ...

  3. linux 下su 和sudo 的用法以及区别

    一. 使用 su 命令临时切换用户身份 1.su 的适用条件和威力 su命令就是切换用户的工具,怎么理解呢?比如我们以普通用户beinan登录的,但要添加用户任务,执行useradd ,beinan用 ...

  4. GOOGLE 离线完整安装包下载地址

    https://support.google.com/chrome/answer/126299?hl=zh-Hans 官方链接介绍 https://www.google.com/chrome/brow ...

  5. 机器学习简易入门(四)- logistic回归

    摘要:使用logistic回归来预测某个人的入学申请是否会被接受 声明:(本文的内容非原创,但经过本人翻译和总结而来,转载请注明出处) 本文内容来源:https://www.dataquest.io/ ...

  6. 第七节:使用实现了dispose模式的类型

    知道类型如何实现dispose模式之后,接下来看一下开发人员怎样使用提供了dispose模式的类型.这里不再讨论前面的SafeHandle类,而是讨论更常用的FileStream类. 可以利用File ...

  7. WebService到底是什么?(转)

    一.序言 大家或多或少都听过WebService(Web服务),有一段时间很多计算机期刊.书籍和网站都大肆的提及和宣传WebService技术,其中不乏很多吹嘘和做广告的成分.但是不得不承认的是Web ...

  8. opengl基础学习专题 (三) 多边形绘制的几种样式

    题外话 聪明人之所以不会成功,是由于他们缺乏坚韧的毅力. ——艾萨克·牛顿(1643年1月4日—1727年3月31日)英国 也许可以理解为 想更深一步的时候,坚持,努力和聪明缺一不可. 挺直腰杆在此向 ...

  9. vim代码补全-spf13,YouCompleteMe

    vim代码补全 现在的图形界面的IDE(Integrated Development Environment)一般具有语法高亮,语法检查,自动补全功能,大大提高了编程的效率. vim作为文本编辑器其强 ...

  10. Environment 类

    提供有关当前环境和平台的信息以及操作它们的方法. 此类不能被继承. using System; using System.Collections; using System.Collections.G ...