什么时候需要版本迁移呢?
答案很简单,什么时候改变数据模型,什么时候就需要版本迁移
.
Core Data
支持对数据模型
(data model)
改变的管理。改变数据模型将造成该数据模型与之前的持久化存储
(stores)
不兼容,而出现错误。所以,如果我们改变了自己的数据模型
,就需要将原有的持久化存储中的数据转移到新的模型版本,这一过程就称为版本迁移(migration)。
为什么需要进行版本迁移?
当我们发布应用之后,再添加一些新的特性,我们将需要更新持久化存储。在我们开发的过程中,很好操作,删除
APP
重新运行程序即可,但是如果用户下载了我们的
APP
,我们就需要注意了,用户肯定不希望存储的数据消失了。所以我们要进行版本迁移,既要保存原有数据又能够添加新功能。
版本迁移的过程
当我们初始化堆栈的时候,其中有一步骤是涉及到添加持久化存储(
store
)到持久化存储协调器(
persistent store coordinator
)。当进行这一步操作的时候,
Core Data
在添加持久化
store
到持久化存储协调器之前做了一些事情:
首先
Core Data
分析了
store
的模型版本(
model version
)。接下来,
Core Data
将会把这个模型版本跟协调器中
配置的
数据模型(
data model
)进行比较。如果持久化存储的模型版本
(store’s model version)
和持久化存储协调器的模型版本不匹配,这时候
Core Data
会根据是否被允许,将决定是否执行迁移
(migration)
操作。
为了进行迁移,我们需要之前的模型版本和当前的模型版本。我们能够创建一个版本模型包含多个数据模型文件,在版本模型中我们需要明确标记哪一个版本为当前使用版本。
Core Data
能够将之前创建的模型版本中的持久化存储,迁移到当前版本。为了帮助
Core Data
实现执行迁移版本,我们必须提供怎样从一个模型版本映射到另一个模型版本的信息。
一旦
Core Data
确定映射模型(
mapping model
),迁移过程将开始。
注意:如果版本迁移并不被允许,而且
持久化存储(
store
)
与
model
是不相容的,
Core Data
将不再把
store
与协调器相关联,而是给定一个合理出错原因
code
。
迁移发生的三个步骤:
1)首先,Core Data
将复制所有的对象,从一个数据
store
到另外一个数据
store
。
2)接下来,Core Data将根据关系映射连接所有相关联的对象。
3
)在目的模型(
destination model
)中强制验证任意数据,在数据复制期间将使目的模型验证失效。
但是如果
迁移
这个过程出现了错误,那么原始的数据存储会怎么样呢?除非迁移完成并且无错误,Core Datac才去除原始数据存储,
迁移所有的数据,
否则
原始数据存储并不会发生变化。
Lightweight Migration
如果我们仅仅是对数据模型进行简单改变
(
比如:为实体添加新的属性
)
,
Core Data
将能够自动进行数据迁移,我们称之为轻量级版本迁移
(lightweight migration).
轻量级版本迁移是不需要我们自己提供映射模型,
Core Data
将推断原始和目的数据模型之间的差别。
轻量级版本迁移对于应用早期的使用是非常方便,当我们改变数据模型,但是我们并不想重新生成数据,我们可以移动存在的数据而不需要为模型版本创建自定义映射模型。
为了Core Data
能够生成推测映射模型,对于数据模型的改变必须符合以下情况,例如:
1
:简单的添加一个新的属性
2
:去除某个属性
3
:非可选属性变成可选属性
4
:可选属性变成非可选属性并定义默认值
5
:重命名实体或者属性
如果我们重命名实体或者属性,我们能够在目的数据模型中设置重命名标识符
(renaming identifier)
来命名源数据相关的视图或者数据。该操作,可以直接在
Xcode Data Modeling tool’s property inspector
中,例如:
1):重命名
Car
实体为
Automobile
2):重命名
Car
的
color
属性为
paintColor
除了上面
5
条之外,
Core Data
还支持如下情况:
6
:添加关系和改变关系类型
1
)我们能够添加一个新的关系或者删除存在的关系
2
)重新命名关系
(
使用重命名标识符跟属性一样
)
3
)改变关系从一对一到一对多,或者从一对多无序到有序,反之同样可以
7
:改变实体的层级关系
1
)我们能够添加,去除,重命名实体
2
)我们能够创建新的父或子实体,而且可以在实体层级中移动属性
3
)我们能够移动实体到层级关系之外,但是我们不能够合并实体层级,如果两个存在的实体在源数据模型中并没有共享父实体,那么在目的数据模型中将不能够共享父实体。
轻量级版本迁移使用步骤:
1:
Open your .xcdatamodel file.
2:Select Editor in the top menu.
3:Select Add Model Version.
4:Select main .xcdatamodel file and open the File Inspector (right-hand panel).
5:Change current version to the new model version you just created.
6:Change addPresistentStoreWithType options.
1:
打开
XCODE
中的
Editor menu
并
select Add Model Version
。将弹出添加版本弹框,类似于下图:
命名可以随意,不过最好还是在原有的名称基础上加后缀,类似于:原名称
+v2, v3, v4
等不同版本。这里需要你选择基于的数据模型。
Xcode
将基于该数据模型创建副本。
这一步骤我们将创建第二个版本的数据模型,但是我们仍然需要告诉
Xcode
使用最新的版本作为当前模型。在
Inspector pan
文件中后侧,找到选择模型版本选项,改为最新的版本名称。如下图:
一旦我们做出这种改变,关注工程导航部分,将看到
little green check mark icon
已经从之前的数据模型转移到了
V2
数据模型。
Core Data
将加载被标记的版本数据,当创建堆栈的时候。老版本在这里就是支持版本的迁移。
2:在自己的CoreData堆栈中添加相关迁移代码,只需要将下面两个key值设置为true,作为options参数传入Core Data堆栈中,然后作为持久化存储对象的options参数。即:
addPersistentStoreWithType(storeType: String, configuration:String?, URL storeURL: NSURL?, options: [NSObject :AnyObject]?) 方法中的options
lazy var stack :CoreDataStack= CoreDataStack(modelName:"UnCloudNotesDataModel", storeName:"UnCloudNotes", options: [NSMigratePersistentStoresAutomaticallyOption:true,
NSInferMappingModelAutomaticallyOption:true])
参数解释:
NSMigratePersistentStoresAutomaticallyOption:简单一点理解就是自动尝试进行版本迁移。该值将告诉Core Data (theNSPersistentStoreCoordinator, actually)开始进行迁移,如果持久化存储模型与当前数据模型并不匹配。Core Data将处理所有细节,寻找原模型创建目的存储文件,所有的步骤都在这两者之间进行。即分配资源、在应用bundle中映射模型,并执行迁移。
NSInferMappingModelAutomaticallyOption:自动创建映射模型。它是lightweight migration所进行的另外一半需要,每次迁移都需要映射模型,这里有一个类比:如果你从一个认识的地方旅游到不认识的地方,你将需要地图告诉你去哪。这里映射模型就是引导。
3:运行程序,现在可以在新的数据模型中添加自己需要的实体和属性等相关内容。
补充一点:
如果我们想确定是否
Core Data
能够在原数据模型和目的数据模型之前推测映射模型,而并没有做一些实际的迁移操作,我们能够
NSMappingModel
的
inferredMappingModelForSourceModel:destinationModel:error:
方法进行推测,如果
Core Data
能够创建映射模型,该方法将返回推测的映射模型,否则为
nil.
为了执行自动迁移,
Core Data
必须能够在运行时找到原数据模型和目的数据模型,如果我们需要把模型放在某个位置,但是并不能够自动发现,这时,我们需要自己使用迁移管理者
(migration manager,NSMigrationManager
实例对象
)
来推测模型并初始化。下面的代码解释了怎样使用迁移管理者来生成推测模型,代码中假定我们已经实现了两个方法
sourceModel
,
destinationModel
并且能够返回各自的数据模型。
- (BOOL)migrateStore:(NSURL *)storeURL toVersionTwoStore:(NSURL *)dstStoreURL error:(NSError **)outError {
// Try to get an inferred mapping model.
NSMappingModel *mappingModel =
[NSMappingModel inferredMappingModelForSourceModel:[self sourceModel]
destinationModel:[self destinationModel] error:outError];
// If Core Data cannot create an inferred mapping model, return NO.
if (!mappingModel) {
return NO;
}
// Create a migration manager to perform the migration.
NSMigrationManager *manager = [[NSMigrationManager alloc]
initWithSourceModel:[self sourceModel] destinationModel:[self destinationModel]];
BOOL success = [manager migrateStoreFromURL:storeURL type:NSSQLiteStoreType
options:nil withMappingModel:mappingModel toDestinationURL:dstStoreURL
destinationType:NSSQLiteStoreType destinationOptions:nil error:outError];
return success;
}
相关推荐文章: