iOS - objective-c中realm的迁移

上一章节中我们学习了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下载
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,233评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,013评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,030评论 0 241
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,827评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,221评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,542评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,814评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,513评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,225评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,497评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,998评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,342评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,986评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,812评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,560评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,461评论 2 266

推荐阅读更多精彩内容