realm 介绍及安装
- 简介
Realm 是一个跨平台的移动终端数据库,支持 iOS(Swift 和 Objective-C 语言都支持)和 Android。Realm 的目的就是提供比 SQLite 和 Core Data 更好更快的数据库支持。它不仅仅是更好和更快,而且更加易于使用,短短几行代码就可以完成很多操作。Realm 完全免费,你可以随意使用它。Realm 是为移动设备而生的,因为在过去的十年中,移动终端的数据库技术没有任何的革新。现在如果和移动终端的数据库打交道,你只有一种选择,使用 SQLite 或者是底层封装了 SQLite 的技术比如 Core Data。Realm 的目的是更加易用,它并不是一个建立在 SQLite 之上的 ORM,而是一个基于自己的持久化引擎,简单并且快速的面向对象移动数据库。
-
安装
同绝大多数的第三方库一样,Realm也支持三种安装方式:- 项目中直接添加xxx.framework 去下载
- CocoaPods
- Charthge
具体安装方式,可参考官方文档:Realm 或 Realm(中文说明)
realm 插件及浏览器
-
Realm插件
使用Realm插件的好处是,可以直接使用xcode创建创建数据模型文件,基本格式也默认搭建好了。
安装方式:
下载 release zip 好后,打开文件中的plugin/RealmPlugin.xcodeproj并进行编译,重启 Xcode之后插件即可生效。如果您使用 Xcode 菜单来建立一个新文件(File > New > File… — or ⌘N) ,您就可以看到有一个新建Realm模型的选项。效果如下:
Realm浏览器:Realm Browser
Realm Browser
可以在appstore直接下载,因为免费,所以,不用再通过任何第三方途径下载安装破解版的。
Realm Browser
可以直接打开.realm的文件,或者直接双击.reaml文件也是默认直接启动Realm Browser
realm 使用及创建
-
创建.realm文件
-
默认文件
let reaml = try! Realm()
这句代码就表示在Docments中创建了一个
default.realm
的文件。下面是Realm()
初始化方法调用的方法,对大家应该有收获:public convenience init() throws { let rlmRealm = try RLMRealm(configuration: RLMRealmConfiguration.default()) self.init(rlmRealm)
}
```-
自定义文件
如果不想使用默认的文件名default.realm
或想自定义不同的.realm
文件,那么看下面代码:-
修改默认的文件名:
// 数据库的默认地址在docments中 var config = Realm.Configuration() config.fileURL = config.fileURL!.deletingLastPathComponent().appendingPathComponent("name.realm") Realm.Configuration.defaultConfiguration = config
-
自定义文件:
// 在docments中创建了一个Realm1.realm的文件 let realm1 = try! Realm(configuration: Realm.Configuration(fileURL: URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!.appending("/Realm1.realm"))))
-
-
-
创建数据模型
-
模型支持的数据类型:
Realm支持以下的属性类型:Bool、Int8、Int16、Int32、Int64、Double、Float、String、NSDate 以及NSData.
CGFloat 属性被取消了,因为它的类型不依赖于平台。
String、NSDate 以及 NSData 类型的属性都可以添加可选值。Object 类型的属性必须设置为可选。存储可空数字可以通过 Realm 可选值来实现。 -
创建模型:
Realm数据模型是基于标准 Swift 类来进行定义的,使用属性来完成模型的具体定义。
通过简单的继承 Object 或者一个已经存在的模型类,您就可以创建一个新的 Realm 数据模型对象。
Realm模型对象在形式上基本上与其他 Swift 对象相同 - 您可以给它们添加您自己的方法(method)和协议(protocol),和在其他对象中使用类似。
主要的限制是某个对象只能在其被创建的那个线程中使用。
如果您安装了我们的Xcode插件 ,那么可在”New File…“对话框中会有一个很漂亮的模板,可用来创建 Swift 文件。import RealmSwift // 狗狗的数据模型 class Dog: Object { dynamic var name = "" dynamic var owner: Person? // 属性可以设置为可选 } // 狗狗主人的数据模型 class Person: Object { dynamic var name = "" dynamic var birthdate = NSDate(timeIntervalSince1970: 1) var dogs = List
() // let dogs = [Dog] () 包含了嵌套关系 }
-
realm 数据增加
- 单个
reaml.add(object: Object, update: Bool)
调用这个方法可以添加对应的数据,object是数据,update,是指插入的数据是否覆盖相同primaryKey的数据,如果为true表示覆盖,如果为false不覆盖,默认为false,这个属性必须是唯一的。
class Dog: Object {
dynamic var type = ""
dynamic var name = ""
dynamic var age = 0
dynamic var id = ""
// 主键,唯一一行被标记的属性
override static func primaryKey()-> String {
return "age" // 必须是属性,必须是不一样的内容
}
override static func ignoredProperties() -> [String] {
return ["type"]
}
}
// 实例化一个dog对象
let dog1 = Dog()
dog1.name = "dogName"
dog1.age = 1
dog1.id = "dog1"
// 获取reaml
let reaml = try! Realm()
// 加入数据
try! reaml.write {
reaml.add(dog1,update: true)
}
-
多个
reaml.add(objects: [Object], update: Bool)
调用这个方法可以添加对应的数据,object是数据,update,是指插入的数据是否覆盖相同primaryKey的数据,如果为true表示覆盖,如果为false不覆盖,默认为false,这个属性必须是唯一的。let dog1 = Dog() dog1.name = "dogName" dog1.age = 1 dog1.id = "dog1" let dog2 = Dog() dog2.name = "dogName" dog2.age = 2 dog2.id = "dog2" let dog3 = Dog() dog3.name = "Name" dog3.age = 3 dog3.id = "dog3" let dog4 = Dog() dog4.name = "dogName" dog4.age = 4 dog4.id = "dog4" let dog5 = Dog() dog5.name = "lastame" dog5.age = 5 dog5.id = "dog5" let reaml = try! Realm() try! reaml.write { reaml.add([dog1,dog2,dog3,dog4,dog5],update: true) }
realm 数据查找
如果您熟悉NSPredicate的话,那么您就能很容易掌握其在 Realm 中的查询方法。Objects、Realm、List 以及 Results 都提供了方法,允许您通过简单地传递一个 NSPredicate 实例、断言字符串或者断言格式化字符串来完成查询这顶Object实例的操作,正如您在 NSArray 中执行查询的哪样。
比如说,下面的例子就展示了如何通过从默认的 Realm 数据库中调用 Results().filter(_:...) 方法来检索所有棕黄色,并且以“大”开头命名的狗狗的:
// 使用断言字符串查询
var tanDogs = realm.objects(Dog).filter("color = '棕黄色' AND name BEGINSWITH '大'")
// 使用 NSPredicate 查询
let predicate = NSPredicate(format: "color = %@ AND name BEGINSWITH %@", "棕黄色", "大")
tanDogs = realm.objects(Dog).filter(predicate)
查看苹果的断言编程指南来获取更多关于断言查询和NSPredicate Cheatsheet的使用信息。 Realm 支持许多常见的断言:
- 比较操作数(comparison operand)可以是属性名称或者某个常量,但至少有一个操作数必须是属性名称;
- 比较操作符 ==、<=、<、>=、>、!=, 以及 BETWEEN 支持 Int, Int8, Int16, Int32, Int64, Float, Double 以及 NSDate 属性类型的比较,比如说 age == 45;
- 相等比较 ==以及!=,比如说Results
().filter("company == %@", company) - 比较操作符 == and != 支持布尔属性;
- 对于 String 和 NSData 属性来说,我们支持 ==、!=、BEGINSWITH、CONTAINS 以及 ENDSWITH 操作符,比如说 name CONTAINS ‘Ja’;
- 字符串支持忽略大小写的比较方式,比如说 name CONTAINS[c] ‘Ja’ ,注意到其中字符的大小写将被忽略;
- Realm 支持以下复合操作符:“AND”、“OR” 以及 “NOT”。比如说 name BEGINSWITH ‘J’ AND age >= 32;
- 包含操作符 IN,比如说 name IN {‘Lisa’, ‘Spike’, ‘Hachi’};
- ==、!=支持与 nil 比较,比如说 Results
().filter("ceo == nil")。注意到这只适用于有关系的对象,这里 ceo 是 Company 模型的一个属性。 - 通过 ==, != 进行空值比较,比如说 Results
().filter("ceo == nil"); 注意,Realm 将 nil 视为一个特殊的值而不是“缺失值”,不像 SQL 那样 nil 等于自身。 - ANY 比较,比如说 ANY student.age < 21 List 以及 Results 属性支持集合表达式:@count、@min、@max、@sum 以及 @avg,例如 realm.objects(Company).filter("employees.@count > 5") 用以寻找所有超过 5 名雇员的公司。
- 支持子查询,不过有限制:
@count 是唯一能应用在 SUBQUERY 表达式中的操作符
SUBQUERY(…).@count 表达式必须与常量进行比较
相关子查询目前还不支持
realm 数据修改
Realm 提供了一系列用以更新数据的方式,这些方式都有着各自所适应的情景。请选择最符合您当前需求的方式来使用:
- 内容直接更新:
您可以在写入事务中通过设置某个对象的属性从而完成对象的更新操作。
// 在一个事务中更新对象
let author = ···
try! realm.write {
author.name = "托马斯·品钦"
}
- 键值对更改:
Object、Result 以及 List都遵守键值编码(Key-Value Coding)(KVC)机制。 当您在运行时才能决定哪个属性需要更新的时候,这个方法是最有用的。
将 KVC 应用在集合当中是大量更新对象的极佳方式,这样就可以不用经常遍历集合,为每个项目创建一个访问器了。
let persons = realm.objects(Person)
try! realm.write {
// 修改一个对象的属性
persons.first?.setValue(true, forKeyPath: "isFirst")
// 将每个人的 planet 属性设置为“地球”
persons.setValue("地球", forKeyPath: "planet")
}
- 通过主键更新
如果您的数据模型中设置了主键的话,那么您可以使用Realm().add(_:update:)来更新对象,或者当对象不存在时插入新的对象。
// 主键,唯一一行被标记的属性
override static func primaryKey()-> String {
return "age" // 必须是属性,必须是不一样的内容
}
class Dog: Object {
dynamic var type = ""
dynamic var name = ""
dynamic var age = 0
dynamic var id = ""
// 主键,唯一一行被标记的属性
override static func primaryKey()-> String {
return "age" // 必须是属性,必须是不一样的内容
}
override static func ignoredProperties() -> [String] {
return ["type"]
}
}
// 实例化一个dog对象
let dog1 = Dog()
dog1.name = "dogName"
dog1.age = 1
dog1.id = "dog1"
// 获取reaml
let reaml = try! Realm()
// 直接更新
try! reaml.write {
reaml.add(dog1,update: true)
}
realm 数据删除
通过在写入事务中将要删除的对象传递给 Realm().delete(_:) 方法,即可完成删除操作。
// let cheeseBook = ... 存储在 Realm 中的 Book 对象
// 在事务中删除一个对象
try! realm.write {
realm.delete(cheeseBook)
}
// 删除多个
let dogs = reaml.objects(Dog.self).filter("age=2")
try! reaml.write {
reaml.delete(dogs)
}
您也能够删除存储在 Realm 中的所有数据。注意,Realm 文件的大小不会被改变,因为它会保留空间以供日后快速存储数据。
// 从 Realm 中删除所有数据
try! realm.write {
realm.deleteAll()
}
realm 数据排序
Results 允许您指定一个排序标准,从而可以根据一个或多个属性进行排序。比如说,下列代码将上面例子中返回的狗狗根据名字升序进行排序:
// 排序名字以“B”开头的棕黄色狗狗
let sortedDogs = realm.objects(Dog.self).filter("color = 'tan' AND name BEGINSWITH 'B'").sorted(byProperty: "name")
realm 通知
Realm 实例将会在每次写入事务提交后,给其他线程上的 Realm 实例发送通知:
// 获取 Realm 通知
let token = realm.addNotificationBlock { notification, realm in
viewController.updateUI()
}
// 随后---一般在deinit方法中调用
token.stop()