前提
以前了解过 Realm 这个第三方数据库操作,但是没有深入的了解。这两天有空花了点时间看了一下文档,这边根据文档摘抄记录一下,方便以后使用到可以查阅。
数据模型
Realm数据模型是基于标准 Objective‑C 类来进行定义的,使用属性来完成模型的具体定义。
通过简单的继承 RLMObject
或者一个已经存在的模型类,您就可以创建一个新的 Realm 数据模型对象。
Realm模型对象在形式上基本上与其他 Objective‑C 对象相同 - 您可以给它们添加您自己的方法(method)和协议(protocol),和在其他对象中使用类似。
主要的限制是某个对象只能在其被创建的那个线程中使用, 并且您无法访问任何存储属性的实例变量(ivar)。
|
|
由于 Realm 中定义的所有模型在程序启动时就会被解析,所以即使代码中没有调用,它们都需要被初始化。
在 Swift 中使用 Realm 的时候,Swift.reflect(_:) 函数可用于确定您模型中的信息,这需要确保 init() 已被成功调用。这意味着所有非可选的属性必须添加一个默认值。
通过 RLMObject 可查看更多细节。
支持的类型
Realm支持以下的属性类型:BOOL
、bool
、int
、NSInteger
、long
、long long
、float
、double
、NSString
、NSDate
、NSData
以及被特殊类型标记)的 NSNumber
。
CGFloat 属性的支持被取消了,因为它不具备平台独立性。
您可以使用RLMArray
在 Xcode 7 以及之后的版本中,RLMArray支持编译时的 Objective‑C 泛型(generics)。下面是不同属性定义方法的意义以及用途:
RLMArray
: 属性类型。<Object *>
: 属性的特别化(generic specialization),这可以阻止在编译时使用错误对象类型的数组。<Object>
: 此RLMArray
遵守的协议,可以让 Realm 知晓如何在运行时确定数据模型的架构。
属性特性(attributes)
注意由于 Realm 在自己的引擎内部有很好的语义解释系统,所以 Objective‑C 的许多属性特性将被忽略,如nonatomic
, atomic
, strong
, copy
和 weak
等。 因此为了避免误解,我们推荐您在编写数据模型的时候不要使用任何的属性特性。 当然,如果您已经设置了这些属性特性,那么在 RLMObject
对象被写入 Realm 数据库前,这些特性会一直生效。 无论 RLMObject
对象是否受到 Realm 管理,您为其编写的自定义 getter 和 setter 方法都能正常工作。
如果您在 Swift 中使用 Objective-C 版本的 Realm 的话,模型的属性前面需要加上 dynamic var
,这是为了让这些属性能够被底层数据库数据所访问。
可空属性(Optional Properties)
通常情况下,NSString *
、NSData *
以及 NSDate *
属性可以设置为 nil
。如果你不需要实现此功能,你可以重写您的 RLMObject
子类的 +requiredProperties
方法。
比如对于以下的模型定义来说,如果尝试给 name
属性设置为 nil
将会抛出一个异常,但是将 birthday
属性设置为 nil
却是允许的:
|
|
存储可空数字目前已经可以通过 NSNumber *
属性完成。
由于 Realm 对不同类型的数字采取了不同的存储格式,因此设置可空的数字属性必须是 RLMInt
、RLMFloat
、RLMDouble
或者 RLMBool
类型。所有赋给属性的值都会被转换为其特定的类型。
比如说,如果我们存储一个用户的年龄(age)而不是存储他们的生日,同时还要允许当您不知道该用户的年龄的时候将 age
属性设置为 nil
:
|
|
RLMProperty
的子类属性始终都可以为 nil
,因此这些类型不能够放在 requiredProperties
中,并且 RLMArray
不支持存储 nil
值。
索引属性(Indexed Properties)
重写 +indexedProperties
方法可以为数据模型中需要添加索引的属性建立索引:
|
|
Realm 支持字符串、整数、布尔值以及 NSDate
属性作为索引。
对属性进行索引可以减少插入操作的性能耗费,加快比较检索的速度(比如说 = 以及 IN 操作符)。
属性默认值
重写+defaultPropertyValues
可以每次在对象创建之后为其提供默认值。
|
|
主键(Primary Keys)
重写 +primaryKey
可以设置模型的主键。声明主键之后,对象将允许进行查询,并且更新速度更加高效,而这也会要求每个对象保持唯一性。 一旦带有主键的对象被添加到 Realm 之后,该对象的主键将不可修改。
|
|
对象存储
对对象的所有更改(添加,修改和删除)都必须通过写入事务(transaction)完成。
Realm 的对象可以被实例化并且作为unmanaged
对象使用(也就是还未添加到 Realm 数据库中的对象),和其他常规Objective‑C对象无异。
如果您想要在多个线程中共享对象,或者在应用重启后重复使用对象,那么您必须将其添加到 Realm 数据库中——这个操作必须在写入事务中完成。
因为写入事务将会产生不可忽略的性能消耗,因此你应当检视你的代码以确保减少写入事务的次数。
由于写入事务像其余硬盘读写操作一样,会出现失败的情况,因此 -[RLMRealm transactionWithBlock:]
以及 -[RLMRealm commitWriteTransaction]
可以选择加上 NSError 指针参数 因此你可以处理和恢复诸如硬盘空间溢出之类的错误。此外,其他的错误都无法进行恢复。简单起见,我们的代码示例并不会处理这些错误,但是您应当在您应用当中注意到这些问题。
创建对象
当定义完数据模型之后,您可以将您的 RLMObject
子类实例化,然后向 Realm 中添加新的实例。我们以下面这个简单的模型为例:
|
|
我们可以用多种方法创建一个新的对象:
|
|
使用指定初始化器(designated initializer)创建对象是最简单的方式。请注意,所有的必需属性都必须在对象添加到 Realm 前被赋值。
通过使用恰当的键值,对象还可以通过字典完成创建。
最后,RLMObject
子类还可以通过数组完成实例化,数组中的值必须和数据模型中对应属性的次序相同。
嵌套属性(Nested Object)
如果某个对象中有 RLMObject
或者 RLMArray
类型的属性,那么通过使用嵌套的数组或者字典便可以对这些属性递归地进行设置。您只需要简单的用表示其属性的字典或者数组替换每个对象即可:
|
|
即使是数组以及字典的多重嵌套,Realm 也能够轻松完成对象的创建。注意 RLMArray
只能够包含 RLMObject
类型,不能包含诸如NSString
之类的基础类型。
添加数据
向 Realm 中添加数据的步骤如下:
|
|
等您将某个对象添加到 Realm 数据库之后,您可以继续使用它,并且您对其做的任何更改都会被保存(必须在一个写入事务当中完成)。当写入事务提交之后,使用相同 Realm 数据源的其他线程才能够对这个对象进行更改。
请注意,如果在进程中存在多个写入操作的话,那么单个写入操作将会阻塞其余的写入操作,并且还会锁定该操作所在的当前线程。
这个特性与其他持久化解决方案类似,我们建议您使用该方案常规的最佳做法:将写入操作转移到一个独立的线程中执行。
由于 Realm 采用了 MVCC 设计架构,读取操作 并不会 因为写入事务正在进行而受到影响。除非您需要立即使用多个线程来同时执行写入操作,不然您应当采用批量化的写入事务,而不是采用多次少量的写入事务。
未完待续。。。
再一次感谢您花费时间阅读这篇文章!
微博: @Danny_吕昌辉
博客: SuperDanny