iOS:Realm的数据迁移

本地迁移

先看一个例子:
假设我们有如下 Person 模型:

@interface Person : RLMObject
@property NSString *firstName;
@property NSString *lastName;
@property int age;
@end

假如我们想要更新数据模型,给它添加一个 fullname 属性, 而不是将“姓”和“名”分离开来。

@interface Person : RLMObject
@property NSString *fullName;
@property int age;
@end

在这个时候如果您在数据模型更新之前就已经保存了数据的话,那么 Realm 就会注意到代码和硬盘上数据不匹配, Realm 就会抛出错误。这时,您必须进行数据迁移以适应新的对象。

迁移方法:
// 此段代码位于 [AppDelegate didFinishLaunchingWithOptions:]

RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
// 设置新的架构版本。必须大于之前所使用的版本
// (如果之前从未设置过架构版本,那么当前的架构版本为 0)
config.schemaVersion = 1;
// 设置模块,如果 Realm 的架构版本低于上面所定义的版本,
// 那么这段代码就会自动调用
config.migrationBlock = ^(RLMMigration *migration, uint64_t oldSchemaVersion) {
    // 我们目前还未执行过迁移,因此 oldSchemaVersion == 0
    if (oldSchemaVersion < 1) {
        // enumerateObjects:block: 方法将会遍历
        // 所有存储在 Realm 文件当中的 `Person` 对象
        [migration enumerateObjects:Person.className
                              block:^(RLMObject *oldObject, RLMObject *newObject) {

        // 将两个 name 合并到 fullName 当中
        newObject[@"fullName"] = [NSString stringWithFormat:@"%@ %@",
                                      oldObject[@"firstName"],
                                      oldObject[@"lastName"]];
        }];
    }
};
[RLMRealmConfiguration setDefaultConfiguration:config];
// 现在我们已经通知了 Realm 如何处理架构变化,
// 打开文件将会自动执行迁移
[RLMRealm defaultRealm];
属性重命名:

下面是一个例子,展示了您该如何在realm中将 Person 的 yearsSinceBirth 属性重命名为 age 属性:

// 此段代码位于 [AppDelegate didFinishLaunchingWithOptions:]

RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
config.schemaVersion = 1;
config.migrationBlock = ^(RLMMigration *migration, uint64_t oldSchemaVersion) {
    // 我们目前还未执行过迁移,因此 oldSchemaVersion == 0
    if (oldSchemaVersion < 1) {
        // 重命名操作必须要在 `enumerateObjects:` 调用之外进行
        [migration renamePropertyForClass:Person.className oldName:@"yearsSinceBirth" newName:@"age"];
    }
};
[RLMRealmConfiguration setDefaultConfiguration:config];

线性迁移注意事项

假如说,我们的应用有两个用户: JP 和 Tim。JP 经常更新应用,但 Tim 却经常跳过某些版本。所以 JP 可能下载过这个应用的每一个版本,并且一步一步地跟着更新构架:第一次下载更新后,数据库架构从 v0 更新到 v1;第二次架构从 v1 更新到 v2…以此类推,井然有序。相反,Tim 很有可能直接从 v0 版本直接跳到了 v2 版本。 因此,您应该使用非嵌套的 if (oldSchemaVersion < X) 结构来构造您的数据库迁移模块,以确保无论用户在使用哪个版本的架构,都能完成必需的更新。

当您的用户不按套路出牌,跳过有些更新版本的时候,另一种情况也会发生。假如您在 v2 里删掉了一个 “email” 属性,然后在 v3 里又把它重新引进了。假如有个用户从 v1 直接跳到 v3,那 Realm 不会自动检测到 v2 的这个删除操作,因为存储的数据架构和代码中的架构吻合。这会导致 Tim 的 Person 对象有一个 v3 的 email 属性,但里面的内容却是 v1 的。这个看起来没什么大问题,但是假如两者的内部存储类型不同(比如说: 从 ISO email 标准格式变成了自定义格式),那麻烦就大了。为了避免这种不必要的麻烦,我们推荐您在 if (oldSchemaVersion < 3) 语句中,清空所有的 email 属性。

参考文档:
Realm官方中文文档
Realm官方英文文档

你可能感兴趣的:(iOS:Realm的数据迁移)