Realm的一些特性介绍

Posted WoodBear009

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Realm的一些特性介绍相关的知识,希望对你有一定的参考价值。

之前做ios开发,数据存储这块基本上用的都是sqllite,15年下半年在做一个产品时,因为时间比较宽裕,便决定在项目中尝试使用realm数据存储框架。之前在做技术调研时,了解到了很多它的优点,速度快、类似core data的机制、文档详尽、简单易用等。而整个项目下来,也确实感觉到了realm的不负众望,优点很多:开发效率得到了大大提高(省去了数据模型与表存储之间转化的很多工作);框架虽然推出不久,但功能覆盖已经趋于完备了,基本都满足了我的需求;有一个十分好用的可视化数据库查看工具;最终的运行表现也很让人满意。但是,在使用中确实也发现了realm框架中存在的一些坑与需要适应的地方的,最近,无意中又回想起了这个框架,发现版本已经更新到了2.1.1,于是决定回顾一下,看看原来的这些地方有没有什么变化,顺便也总结一下这些问题,供大家参考。


1.不支持联合主键

+ (nullable NSString *)primaryKey;
realm不支持数据库中联合主键的概念,如果你之前的设计中用到了联合主键,那只能重新设计,在设计层面上规避这个问题了。


2.不支持自增长主键

同上,设计层面解决


3.不能跨线程共享realm实例

    RLMRealm *realm = [RLMRealm defaultRealm];
    
    Course *course = [[Course alloc] init];
    course.courseId = @"001";
    course.courseName = @"数学";
    [realm beginWriteTransaction];
    [Course createOrUpdateInRealm:realm withValue:course];
    [realm commitWriteTransaction];
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
//        RLMRealm *realm = [RLMRealm defaultRealm];
        [realm beginWriteTransaction];
        Course *course2 = [[Course alloc] init];
        course2.courseId = @"002";
        course2.courseName = @"语文";
        [Course createOrUpdateInRealm:realm withValue:course2];
        [realm commitWriteTransaction];
    );

上面这段代码会运行错误,需要把注释语句打开

Using a Realm Across Threads
To access the same Realm file from different threads, 
you must initialize a new Realm to get a different instance for every thread of your app. As long as you specify the same configuration, all Realm instances will map to the same file on disk

不同线程中,都要创建独立的realm实例,只要配置(configuration)相同,它们操作的就是同一个实体数据库


4.存取只能以对象为单位,不能只查某个属性

使用sql时,可以单独查询某个(几个)独立属性,比如 select courseName from Courses where courseId = "001"

而在realm中 

+ (RLMResults *)objectsWhere:(NSString *)predicateFormat, ...;
+ (RLMResults *)objectsInRealm:(RLMRealm *)realm where:(NSString *)predicateFormat, ...;
+ (RLMResults *)objectsInRealm:(RLMRealm *)realm withPredicate:(nullable NSPredicate *)predicate;
......
查询相关函数,得到的都是对象的集合,相对不够灵活


5.注意RLMResults中的对象

    RLMResults *results = [Course objectsWhere:@"courseId = '001'"];
    Course *getCourse = [results objectAtIndex:0];
    getCourse.courseName = @"英语";

上面代码运行时会产生错误,被查询出的对象,任何的修改都会被直接同步到数据库中,所以对对象的修改都必须被包裹在beginWriteTransaction中,使用时要注意


6.RLMResults与线程

    RLMResults *results = [Course objectsWhere:@"courseId = '001'"];
    Course *getCourse = [results objectAtIndex:0];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
        NSLog(@"%@",results);
        NSLog(@"%@",getCourse.courseName);
    );

上面这段代码会在运行时产生错误,results、getCourse是在主线程中被查询出来的,如果在别的线程中被访问,都是不被允许的

7.Auto-Updating机制

RLMObject instances are live, auto-updating views into the underlying data, which means objects never have to be refreshed. Modifying the properties of an object will immediately reflect in any other instances referring to the same object.

    RLMRealm *realm = [RLMRealm defaultRealm];
    Course *course = [[Course alloc] init];
    course.courseId = @"001";
    course.courseName = @"语文";
    [realm transactionWithBlock:^
        [realm addObject:course];
    ];
    
    Course *getCourse1 = [Course objectsWhere:@"courseId = '001'"].firstObject;
    NSLog(@"%@",getCourse1);
    [realm transactionWithBlock:^
        getCourse1.courseName = @"体育";
    ];
    
    NSLog(@"%@",course);
//    RLMRealm *realm = [RLMRealm defaultRealm];
//    Course *course = [[Course alloc] init];
//    course.courseId = @"001";
//    course.courseName = @"语文";
//    [realm beginWriteTransaction];
//    [Course createOrUpdateInDefaultRealmWithValue:course];
//    [realm commitWriteTransaction];
//    
//    Course *getCourse1 = [Course objectsWhere:@"courseId = '001'"].firstObject;
//    NSLog(@"%@",getCourse1);
//    [realm beginWriteTransaction];
//    getCourse1.courseName = @"数学";
//    [Course createOrUpdateInDefaultRealmWithValue:getCourse1];
//    [realm commitWriteTransaction];
//    NSLog(@"%@",course);

getCourse1进行修改后,course的属性也随之自动更新了.但是,同样的功能逻辑,如果按注释部分的方式去写,auto updating机制却并未起作用,不知道是不是realm框架的问题,所以对auto updating机制的把握还是要多在实践中总结、观察。

    RLMRealm *realm = [RLMRealm defaultRealm];
    Course *course = [[Course alloc] init];
    course.courseId = @"001";
    course.courseName = @"语文";
    [realm beginWriteTransaction];
    [Course createOrUpdateInDefaultRealmWithValue:course];
    [realm commitWriteTransaction];
    
    RLMResults *result = [Course allObjects];
    NSLog(@"%@",result);
    
    Course *course2 = [[Course alloc] init];
    course2.courseId = @"002";
    course2.courseName = @"数学";
    [realm beginWriteTransaction];
    [Course createOrUpdateInDefaultRealmWithValue:course2];
    [realm commitWriteTransaction];
    
    NSLog(@"%@",result);

第一次查询后,result中有一条记录,后面即便没有执行重新查询,新加入的数据,自动就被同步到了result

    RLMRealm *realm = [RLMRealm defaultRealm];
    Course *course = [[Course alloc] init];
    course.courseId = @"001";
    course.courseName = @"语文";
    [realm beginWriteTransaction];
    [Course createOrUpdateInDefaultRealmWithValue:course];
    [realm commitWriteTransaction];
    
    Course *getCourse1 = [Course objectsWhere:@"courseId = '001'"].firstObject;
    NSLog(@"%@",getCourse1);
    Course *getCourse2 = [Course objectsWhere:@"courseId = '001'"].firstObject;
    [realm beginWriteTransaction];
    getCourse2.courseName = @"体育";
    [realm commitWriteTransaction];
    NSLog(@"%@",getCourse1);

开始查询出课程id001的课程模型getCourse1getCourse2的课程名为语文,后面仅对getCourse2进行修改后,getCourse1的属性也被自动同步更新了

    Course *getCourse1 = [Course objectsWhere:@"courseId = '001'"].firstObject;
    NSLog(@"%@",getCourse1);
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^
        RLMRealm *realm = [RLMRealm defaultRealm];
        Course *getCourse2 = [Course objectsWhere:@"courseId = '001'"].firstObject;
        [realm beginWriteTransaction];
        getCourse2.courseName = @"体育";
        [realm commitWriteTransaction];
        NSLog(@"%@",getCourse2);
        dispatch_async(dispatch_get_main_queue(), ^
            NSLog(@"%@",getCourse1);
        );
    );

同样,在别的线程中的修改,也会被同步过来

realm这种auto-updating机制确实十分方便,并保证了数据的实时性,但是在个别情况下,也许这种机制并不是开发者想要的,可能会导致一些意外,开发时需要注意


8.setter/getter方法失效

#import "Course.h"

@implementation Course

-(void)setCourseName:(NSString *)courseName

    _courseName = courseName;


+ (nullable NSString *)primaryKey

    return @"courseId";


@end
Course *getCourse = [Course objectsWhere:@"courseId = '001'"].firstObject;
[realm beginWriteTransaction];
getCourse.courseName = @"英文";//不会走进setCourseName方法
[realm commitWriteTransaction];
从realm数据库读取出的数据模型,setter/getter方法会失效

Since Realm overrides setters and getters to back properties directly by the underlying database, you cannot override them on your objects. 

Note that Realm ignores Objective‑C property attributes likenonatomic,atomic, strong, copy, weak, etc. This is done because Realm has its own optimized storage semantics under the hood. So to avoid being misleading, we recommend writing models without any property attributes at all. However, if you do set property attributes, they will be used until an RLMObject is added to a Realm. Custom names for getters and setters work normally regardless of whether or not anRLMObject is managed by a Realm.










以上是关于Realm的一些特性介绍的主要内容,如果未能解决你的问题,请参考以下文章

iOS 数据库比较:SQLite vs Core Data vs Realm

Shrio02 Realm作用自定义简洁RealmRealm实现类使用

正确处理Android上的Realm实例

做Realm Migration Android的正确方法

ECMASCript 2019可能会有哪些特性?

Puppet 之 八大资源介绍