RealmSwift详解: https://realm.io/cn/docs/swift/latest/#examples
1.Realm数据库,获取Realm数据库的地址
模拟器上: Swift using Realm Swift: (lldb) po Realm.Configuration.defaultConfiguration.fileURL 真机上: Make sure that your device is connected and go to the devices window in the Xcode menu Window > Devices (⌘⇧2). There you will be able to choose your device and your app from a list of installed apps with debugging permissions.
After selecting your app, go to the cog in the toolbar at the bottom of the table view and select “Download Container…“. There you will be able to pull the file from the documents location to your Mac. It will be saved as an xcappdata bundle.
When you open the local path in Finder, where you saved it, you can tap into that by selecting “Show Package Contents” in the context menu of the finder, when you select the file. A new finder window will open, where you find your Realm inside in the following path (e.g.): AppData/Documents/default.realm (The directory '/private/var/mobile' is the path, which is used by iOS on the device filesystem.
2.关于Realm,你要知道下面几点:
(1)使用简单,大部分常用的功能(比如插入、查询等)都可以用一行简单的代码轻松完成,学习成本低。 (2)Realm不是基于Core Data,也不是基于SQLite封装构建的。它有自己的数据库存储引擎。 (3)Realm具有良好的跨平台特性,可以在iOS和Android平台上共同使用。代码可以使用 Swift 、 Objective-C 以及 Java 语言来编写。 (4)Realm 还提供了一个轻量级的数据库查看工具(Realm Browser)。你也可以用它进行一些简单的编辑操作(比如插入和删除操作)
3.数据模型
- 主键:Realm的数据模型可以指定模型的主键.声明主键允许对象的查询和更新更加高效并且会强制要求每个值保持唯一性.(重写 Object.primaryKey())
- 索引属性, Realm允许指定为某个属性建立索引. 这样查询速度回更快.(重写:Object.indexedProperties())
- 被忽略属性:如果不想将模型中某些字段保存在Realm中,可以指定某些属性不被保存.(重写:Object.ignoredProperties())
属性特性:
Realm 模型属性必须使用 @objc dynamic var 特性,从而让其能够访问底层数据库的数据。注意,如果这个类 被 @objcMembers 所声明(Swift 4 以及之后的版本),那么各个属性可以只使用 dynamic var 来声明。
不过有三种例外情况:LinkingObjects、List 以及 RealmOptional。这些属性不能声明为动态类型,因为泛型属性无法在 Objective-C 运行时中正确表示,而这个运行时是用来对 dynamic 属性进行动态调度的。这些属性应当始终用 let 进行声明。
属性备忘单
类型 | 非可空值形式 | 可空值形式 |
---|---|---|
Bool | @objc dynamic var value = false | let value = RealmOptional<Bool>() |
Int | @objc dynamic var value = 0 | let value = RealmOptional<Int>() |
Float | @objc dynamic var value: Float = 0.0 | let value = RealmOptional<Float>() |
Double | @objc dynamic var value: Double = 0.0 | let value = RealmOptional<Double>() |
String | @objc dynamic var value = "" | @objc dynamic var value: String? = nil |
Data | @objc dynamic var value = Data() | @objc dynamic var value: Data? = nil |
Date | @objc dynamic var value = Date() | @objc dynamic var value: Date? = nil |
Object | 不存在:必须是可空值 | @objc dynamic var value: Class? |
List | let value = List<Type>() | 不存在:必须是非可空值 |
LinkingObjects | let value = LinkingObjects(fromType: Class.self, property: "property") | 不存在:必须是非可空值 |
4.操作Realm对象
对象的自更新
Object 实例是底层数据的动态体现,会自动进行更新;因此这意味着无需去刷新对象的当前状态。修改某个对象的属性,会立即影响到所有指向该对象的其他实例。
let myDog = Dog()
myDog.name = "Fido"
myDog.age = 1
try! realm.write {
realm.add(myDog)
}
let myPuppy = realm.objects(Dog.self).filter("age == 1").first
try! realm.write {
myPuppy!.age = 2
}
print("age of my dog: \(myDog.age)") // => 2
模型继承
模型继承不好使,其实是支持继承的, 但是不支持多态.
//可以这样创建一个对象, 参数是字典类型, 字典中包含每个属性的键和值,支持嵌套类型
let duck = Duck(value: [ "animal": [ "age": 3 ], "name": "Gustav" ])
5.增删改查
对象的所有更改(添加/修改/删除)都必须在写入事务内完成.
向 Realm 数据库中添加对象必须在写入事务内完成。由于写入事务将会产生无法忽略的性能消耗,因此您应当检视您的代码,以确保尽可能减少写入事务的数量。Realm 的写入操作是同步以及阻塞进行的,它并不会异步执行。
5.1创建对象
当定义完数据模型之后, 就可以实例化Object
子类了, 然后还可以向Realm中添加新的实例. 实例:
//一个简单的对象
class Dog: Object {
@objc dynamic var name = ""
@objc dynamic var age = 0
}
//1.创建对象, 设置属性
let dog1 = Dog()
dog1.age = 10
dog1.name = "lily"
//2,从字典中创建对象
let dog2 = Dog(value: ["age": 11, "name": "lucy"])
//3,从数组中创建,一定要按顺序
let dog3 = Dog(value: ["dog", 12])
//使用指定初始化函数来创建对象是最直观的方式。
//通过恰当的键值,还可以使用字典来创建对象。
//最后,Object 的子类还可以使用数组来完成实例化。数组中的值必须与数据模型中对应的属性次序相同。
对象创建之后,就可以直接写到数据库中了, 使用如下方法插入数据
获取默认的数据库
let realm = try? Realm()
在事务中向 Realm 数据库中添加数据
try? realm?.write {
realm?.add([dog1, dog2, dog3])
}
//将对象添加到 Realm 数据库之后,您仍然可以继续使用它,并且对其进行的所有更改都会被存储(必须要在写入事务当中进行)。当写入事务提交之后,其他使用同一个 Realm 数据库的线程所做的更改都可以继续进行。
//请注意,写入操作会互相阻塞,并且如果正在执行多个写入操作的话,那么还会将当前线程给阻塞掉。与其它持久化解决方案类似,我们建议您在这种情况下使用通常的最佳做法:将您的写入操作载入到专门的线程中执行。
5.2更新对象
Realm提供一系列更新对象的方法,根据使用场景不同, 都有各自的优缺点.
//1.通常可以在事务中更新属性从而完成更新
// 在事务中更新对象
try! realm.write {
author.name = "Thomas Pynchon"
}
//2.键值编码
//Object、Result 和 List 均允许使用 键值编码(KVC)。 当您需要在运行时决定何种属性需要进行更新的时候, 这个方法就非常有用了。
//批量更新对象时,为集合实现 KVC 是一个很好的做法, 这样就不用承受遍历集合时为每个项目创建访问器 所带来的性能损耗。
let persons = realm.objects(Person.self)
try! realm.write {
persons.first?.setValue(true, forKeyPath: "isFirst")
// 将每个 person 对象的 planet 属性设置为 "Earth"
persons.setValue("Earth", forKeyPath: "planet")
}
//3.通过主键更新
// 创建一个 book 对象,其主键与之前存储的 book 对象相同
let cheeseBook = Book()
cheeseBook.title = "Cheese recipes"
cheeseBook.price = 9000
cheeseBook.id = 1
// 更新这个 id = 1 的 book
try! realm.write {
realm.add(cheeseBook, update: true)
}
// 假设主键为 `1` 的 "Book" 对象已经存在
try! realm.write {
realm.create(Book.self, value: ["id": 1, "price": 9000.0], update: true)
// book 对象的 `title` 属性仍旧保持不变
}
5.3删除对象
在写入事务中,将要删除的对象传递给 Realm().delete(_:) 方法。
// cheeseBook 存储在 Realm 数据库中
// 在事务中删除对象
try! realm.write {
realm.delete(cheeseBook)
}
您同样也可以删除存储在 Realm 数据库当中的所有数据。请注意,Realm 文件会保留在磁盘上所占用的空间,从而为以后的对象预留足够的空间,从而实现快速存储。
//从 Realm 数据库中删除所有对象
try! realm.write {
realm.deleteAll()
}
5.4查询
查询将会返回一个 Results 实例,其中包含了一组 Object 对象。Results 的接口与 Array 基本相同,并且可以使用索引下标来访问包含在 Results 当中的对象。与 Array 所不同的是,Results 只能持有一个 Object 子类类型。
//1.查询所有的Dog对象
let dogs = realm.objects(Dog.self) // 从默认的 Realm 数据库中遍历所有 Dog 对象
//2.条件查询可以使用NSPredicate
// 使用断言字符串来查询
var tanDogs = realm.objects(Dog.self).filter("color = 'tan' AND name BEGINSWITH 'B'")
// 使用 NSPredicate 来查询
let predicate = NSPredicate(format: "color = %@ AND name BEGINSWITH %@", "tan", "B")
tanDogs = realm.objects(Dog.self).filter(predicate)
//3.对查询结果排序
// 对颜色为棕黄色、名字以 "B" 开头的狗狗进行排序
let sortedDogs = realm.objects(Dog.self).filter("color = 'tan' AND name BEGINSWITH 'B'").sorted(byKeyPath: "name")
//按照关键路径进行排序
let ownersByDogAge = dogOwners.sorted(byKeyPath: "dog.age")
//4.支持链式查询
let tanDogs = realm.objects(Dog.self).filter("color = 'tan'")
let tanDogsWithBNames = tanDogs.filter("name BEGINSWITH 'B'")
//5.结果自更新
try! realm.write {
for person in realm.objects(Person.self).filter("age == 10") {
person.age += 1
}
}
//6.限制查询数量
// 循环读取出前 5 个 Dog 对象
// 从而限制从磁盘中读取的对象数量
let dogs = try! Realm().objects(Dog.self)
for i in 0..<5 {
let dog = dogs[i]
// ...
}