Realm从入门到放弃(一)

作者: heweiming 分类: iOS,干货 发布时间: 2016-12-08 23:07

Realm从入门到放弃(一)

最近Realm的确比较火,火是因为它的速度,更因为它是一个比较完善的对象存储方案。当然最最最重要的是它有中文的文档,所以在我大天朝也有不少的猿类在使用这款数据库。

介绍

Realm 是一个跨平台的数据库引擎,为了彻底解决性能问题,Realm并不是在SQLite之上进行开发的ORM,而是由C++打造的一套全新的引擎。因此它的性能比普通的ORM要快很多,在某些方面比SQLite还要快。

Realm 目前支持的语言有Objective-C、Swift、Java、JavaScript跟Xamarin。看上去是移动端的份额比较多。

因为是ORM,所以本身也是为了取代SQLite而存在的一套引擎,设计时也是专门针对移动设备(iOS、Android),学习成本比较低,不过由于Realm本身对数据处理这一块是比较弱的,例如 limit 这个在SQL语句中经常用到的用来分页的功能,在Realm中是没有的,只能通过对应的操作自己的限制数量。

一、性能

评价:碾压级 数据来自 Realm的官方介绍
cout对比图

该图是20万条数据中进行查询并且count。而Realm可以每秒进行30.9次查询并且count。这数据在主流的移动数据库中不可谓不逆天。



queries对比图

有了count怎么可能没有queries,Realm在queries中跟count的数据几乎是一样的。也是跟其他主流移动数据中拉了很大的差距。



Inserts对比图

Inserts对比中可以发现Sqlite的速度终于领先了Realm,不过原因,我猜应该是线程安全的问题。而同样是主流的基于Sqlite封装的FMDB性能竟然是原生的四分之一,是Realm的二分之一。

今天先说我比较熟悉的Objective-C好了

首先我们来看一下 Realm 的官网。Realm 一眼看上起全是英文,不过呢,在网站的右上角有个小地球,只需要稍微切换一下,就立刻回到我大天朝时代了。不过身为猿类,学会并且习惯看英文文档是一个很重要的技能。

二、易用性

评价:友好 数据来自:Realm-Objc官方文档

说是友好是因为Realm提供了中文文档,虽然中文文档不是最新的,但是足够我们进坑和爬坑用了。

不过要说的一个点是Realm的代码入侵性比较强,如果不是全新的项目而是老项目,要转过来要慎重考虑。还有Realm是没有多表查询这个说法的,也没有连表的说法,所以如果你的客户端逻辑比较复杂,我建议还是不要用Realm。

Realm 的用法很简单,其实只需要把你需要存储的模型(NSObject)继承RLMObject。如果是新项目的话这个是没问题的,但是如果是老项目,已经用其他数据库做了大量的存储的话。那就得花一点时间了把模型改过来了。模型里面如果有NSMutableArray或者NSArray的属性,那就得改成RLMArray并且在属性接口文件end后面加上RLM_ARRAY_TYPE(ModelName)才可以。

范例:

#import <Realm/Realm.h>

@class Person;

// Dog model
@interface Dog : RLMObject
@property NSString *name;
@property Person   *owner;
@end
RLM_ARRAY_TYPE(Dog) // define RLMArray<Dog>

// Person model
@interface Person : RLMObject
@property NSString             *name;
@property NSDate               *birthdate;
@property RLMArray<Dog *><Dog> *dogs;
@end
RLM_ARRAY_TYPE(Person) // define RLMArray<Person>

// Implementations
@implementation Dog
@end // none needed

@implementation Person
@end // none needed

Realm支持的数据类型有:BOOL, bool, int, NSInteger, long, long long, float, double, NSString, NSDate, NSData, and NSNumber。

三、工具

评价:精致 数据来自:Realm-Objc官方文档

Realm 提供一个很棒的MAC上的数据库浏览工具叫做 Realm Browser。这个数据浏览器可以承担阅读与修改Realm产生的数据库文件 .realm。而且它有一个很好的特性,如果你已经用RealmBrowser打开了数据库文件,无论你的数据怎么改,你重新run一次代码,Realm Broswer是可以即时捕捉,并且不用重新找到沙盒再找到.realm然后重新打开。

Realm Browser

Realm 还进行了大部分的开源,如果有兴趣的人可以去参考一下github

Realm 除了提供使用文档,还提供了API文档

四、功能性

评价:3星 数据来自:Realm-Objc官方文档

数据库这种比较核心的东西,不是说随便想换就换,所以得有几个维度去考虑这些问题:

1.性能必须得比目前的高

2.数据迁移比较简单

3.有完善的文档与API

4.代码入侵性不高

下面来看一下Realm到底有什么功能:


索引属性(Indexed Properties)


重写 +indexedProperties 方法可以为数据模型中需要添加索引的属性建立索引:

@interface Book : RLMObject
@property float price;
@property NSString *title;
@end

@implementation Book
+ (NSArray *)indexedProperties {
  return @[@"title"];
}
@end

Realm 支持字符串、整数、布尔值以及 NSDate 属性作为索引。

对属性进行索引可以减少插入操作的性能耗费,加快比较检索的速度(比如说 = 以及 IN 操作符)。

属性默认值


重写+defaultPropertyValues 可以每次在对象创建之后为其提供默认值。

@interface Book : RLMObject
@property float price;
@property NSString *title;
@end

@implementation Book
+ (NSDictionary *)defaultPropertyValues {
    return @{@"price" : @0, @"title": @""};
}
@end

对象的自更新特性

RLMObject 实例是底层数据的动态表现,其会进行自动更新,这意味着对象不需要进行刷新。修改某个对象的属性会立刻影响到其他所有指向同一个对象的实例。

Dog *myDog = [[Dog alloc] init];
myDog.name = @"小白";
myDog.age = 1;

[realm transactionWithBlock:^{
  [realm addObject:myDog];
}];

Dog *myPuppy = [[Dog objectsWhere:@"age == 1"] firstObject];
[realm transactionWithBlock:^{
  myPuppy.age = 2;
}];

myDog.age; // => 2

RLMObject 的这个特性不仅让 Realm 保证速度和效率,它同时还让代码更加简洁、更为灵活。比如说,如果您的 UI 代码是基于某个特定的 Realm 对象来现实的,那么在触发 UI 重绘之前,您不用担心数据的刷新或者重新检索等问题。

主键(Primary Keys)

重写 +primaryKey 可以设置模型的主键。声明主键之后,对象将允许进行查询,并且更新速度更加高效,而这也会要求每个对象保持唯一性。 一旦带有主键的对象被添加到 Realm 之后,该对象的主键将不可修改。

@interface Person : RLMObject
@property NSInteger id;
@property NSString *name;
@end

@implementation Person
+ (NSString *)primaryKey {
    return @"id";
}
@end

忽略属性(Ignored Properties)

重写 +ignoredProperties 可以防止 Realm 存储数据模型的某个属性。Realm 将不会干涉这些属性的常规操作,它们将由成员变量(ivar)提供支持,并且您能够轻易重写它们的 setter 和 getter。

@interface Person : RLMObject
@property NSInteger tmpID;
@property (readonly) NSString *name; // 只读属性将被自动忽略
@property NSString *firstName;
@property NSString *lastName;
@end

@implementation Person
+ (NSArray *)ignoredProperties {
    return @[@"tmpID"];
}
- (NSString *)name {
    return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];
}
@end

忽略属性的行为与 Objective-C 或者 Swift 类当中的普通对象相似。它们并不支持任何一种 Realm 特定的功能。例如,无法通过查询来检索忽略属性,也无法实现自动更新,即便另一个相同对象的实例的忽略属性值发生了变更。此外忽略属性发生更改的时候也不会触发通知,尽管仍然可以使用 KVO 来实现简直观察。

可空属性(Optional Properties)

通常情况下,NSString 、NSData 以及 NSDate * 属性可以设置为 nil。如果你不需要实现此功能,你可以重写您的 RLMObject 子类的 +requiredProperties 方法。

比如对于以下的模型定义来说,如果尝试给 name 属性设置为 nil 将会抛出一个异常,但是将 birthday 属性设置为 nil 却是允许的:

@interface Person : RLMObject
@property NSString *name;
@property NSDate *birthday;
@end

@implementation Person
+ (NSArray *)requiredProperties {
    return @[@"name"];
}
@end

存储可空数字目前已经可以通过 NSNumber * 属性完成。

由于 Realm 对不同类型的数字采取了不同的存储格式,因此设置可空的数字属性必须是 RLMInt、RLMFloat、RLMDouble 或者 RLMBool 类型。所有赋给属性的值都会被转换为其特定的类型。

请注意,NSDecimalNumber 的值只能分配给类型为 RLMDouble 的 Realm 属性,此外 Realm 将会存储近似于双精度浮点的数值,而不是存储基本的十进制数值。

比如说,如果我们存储一个用户的年龄(age)而不是存储他们的生日,同时还要允许当您不知道该用户的年龄的时候将 age 属性设置为 nil:

@interface Person : RLMObject
@property NSString *name;
@property NSNumber<RLMInt> *age;
@end

@implementation Person
+ (NSArray *)requiredProperties {
    return @[@"name"];
}
@end

RLMProperty 的子类属性始终都可以为 nil,因此这些类型不能够放在 requiredProperties中,并且 RLMArray 不支持存储 nil 值。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

4条评论
  • heweiming

    2017年4月16日 下午3:01

    自顶

  • Just want to say your article is as surprising. The clearness in your post is simply spectacular and i can assume you’re an expert on this subject.
    Well with your permission allow me to grab your RSS feed to keep updated with
    forthcoming post. Thanks a million and please continue the rewarding work.

  • Gpa Calculator Online Free

    2017年5月6日 上午5:45

    Hello would you mind letting me know which web host you’re utilizing?

    I’ve loaded your blog in 3 different web browsers and I must say this blog
    loads a lot quicker then most. Can you recommend
    a good web hosting provider at a reasonable price?
    Thanks a lot, I appreciate it!

    1. heweiming

      2017年5月11日 下午7:20

      The host is aliyun

发表评论

电子邮件地址不会被公开。 必填项已用*标注

标签云