美文网首页
iOS - objective-c中realm的迁移

iOS - objective-c中realm的迁移

作者: 翀鹰精灵 | 来源:发表于2021-01-30 13:09 被阅读0次

    上一章节中我们学习了objective-c中realm的对应关系,例子中我们涉及到两种模型关系的对应,但是很多实际项目开发中,我们还会涉及到数据库迁移的问题。我们一起来让我们来探索 Realm 中数据库迁移的方案。

    数据库迁移大致分为以下几种情况:
    1.数据结构迁移
    2.数据迁移
    3.属性重命名
    4.多版本增量迁移

    场景一:

    • 一 . 数据结构迁移

    比如一个MigrationModel的表,表中只有age和name两个字段,这个时候我们需要增加一个fullName的字段,也就是说现在MigrationModel表中变成了age,name,fullName三个字段, 这时候需要用到数据结构迁移。

    原来模型

    //
    //  MigrationModel.h
    //  realm_oc_demo
    //
    //  Created by allison on 2021/1/24.
    //
    
    #import <Realm/Realm.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface MigrationModel : RLMObject
    
    @property NSString *name;
    
    @property int age;
    @end
    
    NS_ASSUME_NONNULL_END
    

    创建数据库方法

    - (void)viewDidLoad {
        [super viewDidLoad];
    
        [self setDefaultRealmForUser:@"zhangsan"];
        [self migrationAction];
    }
    
    ///数据库迁移
    - (void)migrationAction {
        NSLog(@"数据库路径:%@",[[RLMRealmConfiguration defaultConfiguration]fileURL]);
        MigrationModel *model = [[MigrationModel alloc]init];
        model.name = @"Allison";
        model.age = 18;
        RLMRealm *realm = [RLMRealm defaultRealm];
        [realm transactionWithBlock:^{
            [realm addObject:model];
        }];
        
    }
    
    - (void)setDefaultRealmForUser:(NSString *)userName {
        RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
        //使用默认的目录,但是使用用户名来替换默认的文件名
        config.fileURL = [[[config.fileURL URLByDeletingLastPathComponent]URLByAppendingPathComponent:userName]URLByAppendingPathExtension:@"realm"];
        //将这个配置应用到默认的realm数据库中
        [RLMRealmConfiguration setDefaultConfiguration:config];
    }
    
    

    此时运行demo我们发现数据结构如下所示:

    01.png

    新需求:增加一个fullName的字段,需要在这个表中插入一个fullName的字段,这里就数据到数据结构迁移了。

    新模型

    #import <Realm/Realm.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface MigrationModel : RLMObject
    //新增字段
    @property NSString *fullName;
    
    @property NSString *name;
    
    @property int age;
    @end
    
    NS_ASSUME_NONNULL_END
    

    此时如果直接运行,就会出现下面的报错:

    02.png

    Terminating app due to uncaught exception 'RLMException', reason: 'Migration is required due to the following errors:
    这个错误的意思就是数据结构发生了变化,所以我们需要加上迁移的逻辑,并且将版本号+1(版本号默认为0),此时我们可以设置为1.

    数据迁移代码如下:

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
        self.window.backgroundColor = [UIColor whiteColor];
        ViewController *vc = [[ViewController alloc]init];
        UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:vc];
        self.window.rootViewController = nav;
        [self migrationRealmAction];
        return YES;
    }
    
    #pragma mark -- <迁移数据库>
    - (void)migrationRealmAction {
    
        NSLog(@"数据库路径:%@",[[RLMRealmConfiguration defaultConfiguration]fileURL]);
        //1.获取默认配置
        RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
        //2.叠加版本号(要比上一次版本号高)
        int newVersion = 1;
        config.schemaVersion = newVersion;
        //3.迁移步骤
        [config setMigrationBlock:^(RLMMigration * _Nonnull migration, uint64_t oldSchemaVersion) {
                if (oldSchemaVersion < newVersion) {
                    NSLog(@"--需要迁移--oldSchemaVersion:%llu migration:%@",oldSchemaVersion,migration);
                }
        }];
        //4.让配置生效
        [RLMRealmConfiguration setDefaultConfiguration:config];
        //5.需要立即迁移
        [RLMRealm defaultRealm];
    }
    

    再次运行,数据迁移后的效果如下图所示:

    03.png

    至此数据结构迁移到此完成。

    场景二:

    刚刚情形1中的场景数据迁移仅仅需要5个步骤即可,比较简单,但是有些场景,新增的字段,是需要保留之前老字段的内容的,比如MigrationModel表中新增一个detailInfo详细信息,detailInfo = age + name + "地址信息"。

    老模型

    @interface MigrationModel : RLMObject
    //新增字段
    @property NSString *fullName;
    
    @property NSString *name;
    
    @property int age;
    @end
    

    新模型

    @interface MigrationModel : RLMObject
    //新增字段
    @property NSString *detailInfo;
    
    @property NSString *fullName;
    
    @end
    

    此时我们detailInfo字段的内容,要从之前的老字段age和name中获得,所以这个时候迁移的时候就需要遍历之前老的字段并取出赋值。

    迁移核心代码如下所示:

    #pragma mark -- <迁移数据库>
    - (void)migrationRealmAction {
    
        NSLog(@"数据库路径:%@",[[RLMRealmConfiguration defaultConfiguration]fileURL]);
        //1.获取默认配置
        RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
        //2.叠加版本号(要比上一次版本号高)
        int newVersion = 5;
        config.schemaVersion = newVersion;
        //3.迁移步骤
        [config setMigrationBlock:^(RLMMigration * _Nonnull migration, uint64_t oldSchemaVersion) {
                if (oldSchemaVersion < newVersion) {
                    NSLog(@"--需要迁移--oldSchemaVersion:%llu migration:%@",oldSchemaVersion,migration);
                    [migration enumerateObjects:@"MigrationModel" block:^(RLMObject * _Nullable oldObject, RLMObject * _Nullable newObject) {
                        newObject[@"detailInfo"] = [NSString stringWithFormat:@"%@ %@ 详细地址XXX ",oldObject[@"age"],oldObject[@"name"]];
                    }];
                }
        }];
        //4.让配置生效
        [RLMRealmConfiguration setDefaultConfiguration:config];
        //5.需要立即迁移
        [RLMRealm defaultRealm];
    
    }
    

    效果如图4所示

    04.png

    场景三:重命名字段

    重命名字段与【场景2】类似,不再赘述。

    场景四:多版本增量迁移

    指的是原来我APP中有1.0的数据库,我现在需要升级到2.0。这里升级还是类似场景2,只不过需要判断版本的型号,分开来处理即可。

    例:
    版本0 有三个字段

    @interface MigrationModel : RLMObject
    @property NSString *firstName;//姓氏
    @property NSString *lastName;//名字
    @property int age;
    @end
    

    版本1 有2个字段
    fullName = firstName + lastName

    @interface MigrationModel : RLMObject
    @property NSString *fullName;//新增字段
    @property int age;
    @end
    

    版本2也 有2个字段

    @interface MigrationModel : RLMObject
    @property NSString *email;//新增字段
    @property int age;
    @end
    

    问:此时如何做迁移
    以下是多版本迁移的核心代码

       //3.迁移步骤
       [config setMigrationBlock:^(RLMMigration * _Nonnull migration, uint64_t oldSchemaVersion) {
               if (oldSchemaVersion < newVersion) {
                   if (oldSchemaVersion < 1) {
                       [migration enumerateObjects:@"MigrationModel" block:^(RLMObject * _Nullable oldObject, RLMObject * _Nullable newObject) {
                           newObject[@"detailInfo"] = [NSString stringWithFormat:@"%@ %@",oldObject[@"age"],oldObject[@"name"]];
                       }];
                   }
                   if (oldSchemaVersion < 2) {
                       [migration enumerateObjects:@"MigrationModel" block:^(RLMObject * _Nullable oldObject, RLMObject * _Nullable newObject) {
                           newObject[@"email"] = @"xxxx";
                       }];
                   }        
               }
       }];
    

    END.

    DEMO下载

    相关文章

      网友评论

          本文标题:iOS - objective-c中realm的迁移

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