美文网首页
iOS:Realm的数据迁移

iOS:Realm的数据迁移

作者: kangyiii | 来源:发表于2017-11-29 17:53 被阅读0次

    本地迁移

    先看一个例子:
    假设我们有如下 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的数据迁移

          本文链接:https://www.haomeiwen.com/subject/oucpbxtx.html