Swift-Realm数据库的使用详解

概述

Realm 是一个跨平台的移动数据库引擎,其性能要优于 Core Data 和 FMDB - 移动端数据库性能比较, 我们可以在 Android 端 realm-java,iOS端:Realm-Cocoa,同时支持 OC 和 Swift两种语言开发。其使用简单,免费,性能优异,跨平台的特点广受程序员GG喜爱。

Realm 中文文档

本文将结合一些实战演练讲解 Realm 的用法,干货满满!

Realm 支持如下属性的存储

  • Int,Int8,Int16,Int32 和 Int64
  • Boolean 、 Bool
  • Double 、 Float
  • String
  • NSDate 、 Date(精度到秒)
  • NSData 、 Data
  • 继承自 Object 的类 => 作为一对一关系(Used for One-to-one relations)
  • List => 作为一对多关系(Used for one-to-many relations)

如下表是在代码中声明的实例:

类型 非可选值形式 可选值形式
Bool dynamic var value = false let value = RealmOptional()
Int dynamic var value = 0 let value = RealmOptional()
Float dynamic var value: Float = 0.0 let value = RealmOptional()
Double dynamic var value: Double = 0.0 let value = RealmOptional()
String dynamic var value = "" dynamic var value: String? = nil
Data dynamic var value = NSData() dynamic var value: NSData? = nil
Date dynamic var value = NSDate() dynamic var value: NSDate? = nil
Object 必须是可选值 dynamic var value: Class?
List let value = List() 必须是非可选值
LinkingObjects let value = LinkingObjects(fromType: Class.self, property: "property") 必须是非可选值

Realm 安装 - 使用 CocoaPods

pod 'RealmSwift'
pod 'Realm'

Realm 配置

  • 将以下代码写在 AppDelegate 的 didFinishLaunchingWithOptions 方法中,这个方法主要用于数据模型属性增加或删除时的数据迁移,每次模型属性变化时,将 dbVersion 加 1 即可,Realm 会自行检测新增和需要移除的属性,然后自动更新硬盘上的数据库架构,移除属性的数据将会被删除。
/// 配置数据库
public class func configRealm() {
/// 如果要存储的数据模型属性发生变化,需要配置当前版本号比之前大
let dbVersion : UInt64 = 2
let docPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)[0] as String
let dbPath = docPath.appending("/defaultDB.realm")
let config = Realm.Configuration(fileURL: URL.init(string: dbPath), inMemoryIdentifier: nil, syncConfiguration: nil, encryptionKey: nil, readOnly: false, schemaVersion: dbVersion, migrationBlock: { (migration, oldSchemaVersion) in }, deleteRealmIfMigrationNeeded: false, shouldCompactOnLaunch: nil, objectTypes: nil)
Realm.Configuration.defaultConfiguration = config
Realm.asyncOpen { (realm, error) in
if let _ = realm {
print("Realm 服务器配置成功!")
}else if let error = error {
print("Realm 数据库配置失败:\(error.localizedDescription)")
}
}
}
复制代码

定义模型

import UIKit
import RealmSwift class Book: Object {
@objc dynamic var name = ""
@objc dynamic var author = "" /// LinkingObjects 反向表示该对象的拥有者
let owners = LinkingObjects(fromType: Student.self, property: "books")
} class Student: Object {
@objc dynamic var name = ""
@objc dynamic var age = 18
@objc dynamic var weight = 156
@objc dynamic var id = 0
@objc dynamic var address = ""
@objc dynamic var birthday : NSDate? = nil
@objc dynamic var photo : NSData? = nil //重写 Object.primaryKey() 可以设置模型的主键。
//声明主键之后,对象将被允许查询,更新速度更加高效,并且要求每个对象保持唯一性。
//一旦带有主键的对象被添加到 Realm 之后,该对象的主键将不可修改。
override static func primaryKey() -> String? {
return "id"
} //重写 Object.ignoredProperties() 可以防止 Realm 存储数据模型的某个属性
override static func ignoredProperties() -> [String] {
return ["tempID"]
} //重写 Object.indexedProperties() 方法可以为数据模型中需要添加索引的属性建立索引,Realm 支持为字符串、整型、布尔值以及 Date 属性建立索引。
override static func indexedProperties() -> [String] {
return ["name"]
} //List 用来表示一对多的关系:一个 Student 中拥有多个 Book。
let books = List<Book>()
} 复制代码

需要注意的是:在使用Realm中存储的数据模型都要是 Object 类的子类。

1) 设置主键 - primaryKey

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

    override static func primaryKey() -> String? {
return "id"
}
复制代码

2) 忽略属性 - ignoredProperties

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

    override static func ignoredProperties() -> [String] {
return ["tempID"]
}
复制代码

3)索引属性 - indexedProperties

重写 Object.indexedProperties() 方法可以为数据模型中需要添加索引的属性建立索引,Realm 支持为字符串、整型、布尔值以及 Date 属性建立索引。

    override static func indexedProperties() -> [String] {
return ["name"]
}
复制代码

4)使用List实现一对多关系 - indexedProperties

List 用来表示一对多的关系:一个 Student 中拥有多个 Book。
List 中可以包含简单类型的 Object,表面上和可变的 Array 非常类似,所用的方法和访问数据的方式(索引和下标)都相同,并且所包含的所有对象都应该是相同类型的。声明前面不可加 dynamic ,因为在 swift 运行时无法表示泛型属性。
注意:List 只能够包含 Object 类型,不能包含诸如String之类的基础类型。

    //List 用来表示一对多的关系:一个 Student 中拥有多个 Book。
let books = List<Book>()
复制代码

5)反向关系 - LinkingObjects

通过反向关系(也被称为反向链接(backlink)),您可以通过一个特定的属性获取和给定对象有关系的所有对象。 Realm 提供了“链接对象 (linking objects)” 属性来表示这些反向关系。借助链接对象属性,您可以通过指定的属性来获取所有链接到指定对象的对象。
例如:一个 Book 对象可以拥有一个名为 owners 的链接对象属性,这个属性中包含了某些 Student 对象,而这些 Student 对象在其 books 属性中包含了这一个确定的 Book 对象。您可以将 owners 属性设置为 LinkingObjects 类型,然后指定其关系,说明其当中包含了其拥有者 Student 对象。

  let owners = LinkingObjects(fromType: Student.self, property: "books")
复制代码

1 增

1.1 需求: 插入 1 名学生信息到本地数据库?

import UIKit
import RealmSwift
class XWStudentRealmTool: Object {
private class func getDB() -> Realm {
let docPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)[0] as String
let dbPath = docPath.appending("/defaultDB.realm")
/// 传入路径会自动创建数据库
let defaultRealm = try! Realm(fileURL: URL.init(string: dbPath)!)
return defaultRealm
}
}
/// 增
extension XWStudentRealmTool { public class func insertStudent(by student : Student) -> Void {
let defaultRealm = self.getDB()
try! defaultRealm.write {
defaultRealm.add(student)
}
print(defaultRealm.configuration.fileURL ?? "")
}
}
复制代码
测试代码
  func testInsterStudent() {
let stu = Student()
stu.name = "极客学伟"
stu.age = 26
stu.id = 2; let birthdayStr = "1993-06-10"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "YYYY-MM-dd"
stu.birthday = dateFormatter.date(from: birthdayStr)! as NSDate stu.weight = 160
stu.address = "回龙观" XWStudentRealmTool.insertStudent(by: stu)
}
复制代码

通过 Realm Browser 查看刚才保存的数据
通过 print(realm.configuration.fileURL ?? "") 打印数据路径

效果:

1.2 需求: 测试在数据库中插入一个拥有多本书并且有头像的学生对象

测试代码
//测试在数据库中插入一个拥有多本书并且有头像的学生对象
func testInsertStudentWithPhotoBook() {
let stu = Student()
stu.name = "极客学伟_有头像_有书"
stu.weight = 151;
stu.age = 26
stu.id = 3;
// 头像
stu.setPhotoWitName("cat") let bookFubaba = Book.init(name: "富爸爸穷爸爸", author: "[美]罗伯特.T.清崎")
let bookShengmingbuxi = Book.init(name: "生命不息, 折腾不止", author: "罗永浩")
let bookDianfuzhe = Book(value: ["颠覆着: 周鸿祎自传","周鸿祎"])
stu.books.append(bookFubaba);
stu.books.append(bookShengmingbuxi);
stu.books.append(bookDianfuzhe); XWStudentRealmTool.insertStudent(by: stu)
}
复制代码

运行结果:
会自动创建数据库并新建两个表 Student 和 Book, 并将两者进行关联

1.3 需求: 测试在数据库中插入44个的学生对象

保存方法

/// 保存一些Student
public class func insertStudents(by students : [Student]) -> Void {
let defaultRealm = self.getDB()
try! defaultRealm.write {
defaultRealm.add(students)
}
print(defaultRealm.configuration.fileURL ?? "")
}
复制代码
测试代码
    //测试在数据库中插入多个拥有多本书并且有头像的学生对象
func testInsertManyStudent() {
var stus = [Student]() for i in 100...144 {
let stu = Student()
stu.name = "极客学伟_\(i)"
stu.weight = 151;
stu.age = 26
stu.id = i;
// 头像
stu.setPhotoWitName("cat")
let birthdayStr = "1993-06-10"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "YYYY-MM-dd"
stu.birthday = dateFormatter.date(from: birthdayStr)! as NSDate
stus.append(stu)
} XWStudentRealmTool.insertStudents(by: stus)
}
复制代码

演示结果:

2 查

2.1 普通查询: 查询数据库中所有学生模型并输出姓名,图片,所拥有的书信息

  /// 获取 所保存的 Student
public class func getStudents() -> Results<Student> {
let defaultRealm = self.getDB()
return defaultRealm.objects(Student.self)
}
复制代码
测试代码
     let stus = XWStudentRealmTool.getStudents()
for stu in stus {
print(stu.name)
if stu.photo != nil {
self.imageV.image = stu.getPhotoImage()
}
if stu.books.count > 0 {
for book in stu.books {
print(book.name + "+" + book.author)
}
}
}
复制代码

演示结果:
输出姓名和书籍信息

将获取的头像为imageView赋值

2.2 主键查询: 查询数据库中id 为 110 的学生模型并输出姓名

    /// 获取 指定id (主键) 的 Student
public class func getStudent(from id : Int) -> Student? {
let defaultRealm = self.getDB()
return defaultRealm.object(ofType: Student.self, forPrimaryKey: id)
}
复制代码
测试代码
 // 通过主键查询
func testSearchStudentByID(){
let student = XWStudentRealmTool.getStudent(from: 110)
if let studentL = student {
print(studentL.name)
}
}
复制代码

演示结果:

对应数据库中:

2.2 主键查询: 查询数据库中id 为 110 的学生模型并输出姓名

    /// 获取 指定条件 的 Student
public class func getStudentByTerm(_ term: String) -> Results<Student> {
let defaultRealm = self.getDB()
print(defaultRealm.configuration.fileURL ?? "")
let predicate = NSPredicate(format: term)
let results = defaultRealm.objects(Student.self)
return results.filter(predicate)
}
复制代码
测试代码
    // 条件查询
func testSearchTermStudent() {
let students = XWStudentRealmTool.getStudentByTerm("name = '极客学伟_110'")
if students.count == 0 {
print("未查询到任何数据")
return
}
for student in students {
print(student.name,student.weight)
}
}
复制代码

输出结果:

升序/降序 查询

// 根据名字升序查询
let stus = realm.objects(Student.self).sorted(byKeyPath: "id") // 根据名字降序序查询
let stus = realm.objects(Student.self).sorted(byKeyPath: "id", ascending: false) 复制代码

3 改

3.1 主键更新 - 更新单个学生

    /// 更新单个 Student
public class func updateStudent(student : Student) {
let defaultRealm = self.getDB()
try! defaultRealm.write {
defaultRealm.add(student, update: true)
}
}
复制代码

3.2 主键更新 - 更新多个学生

    /// 更新多个 Student
public class func updateStudent(students : [Student]) {
let defaultRealm = self.getDB()
try! defaultRealm.write {
defaultRealm.add(students, update: true)
}
}
复制代码

测试代码

    /// 批量更改
func testUpdateStudents() {
var stus = [Student]()
for i in 100...144 {
let stu = Student()
stu.name = "极客学伟改名_\(i)"
stu.weight = 148;
stu.age = 27
stu.id = i;
stus.append(stu)
}
XWStudentRealmTool.updateStudent(students: stus)
}
复制代码

更新之前:

更新之后:

3.3 键值更新 - 所有学生 年龄 改为 18

    /// 更新多个 Student
public class func updateStudentAge(age : Int) {
let defaultRealm = self.getDB()
try! defaultRealm.write {
let students = defaultRealm.objects(Student.self)
students.setValue(age, forKey: "age")
}
}
复制代码

测试代码:

    /// 批量更改年龄
func testUpdateStudentsAge() {
XWStudentRealmTool.updateStudentAge(age: 18)
}
复制代码

演示结果:

4 删

     /// 删除单个 Student
public class func deleteStudent(student : Student) {
let defaultRealm = self.getDB()
try! defaultRealm.write {
defaultRealm.delete(student)
}
} /// 删除多个 Student
public class func deleteStudent(students : Results<Student>) {
let defaultRealm = self.getDB()
try! defaultRealm.write {
defaultRealm.delete(students)
}
}
复制代码

测试代码:

    /// 删除id 为 3 的学生
func testDeleteOneStudent() {
let stu = XWStudentRealmTool.getStudent(from: 3)
if stu != nil {
XWStudentRealmTool.deleteStudent(student: stu!)
}
} /// 删除所有
func testDeleteAllStudent() {
let stus = XWStudentRealmTool.getStudents()
XWStudentRealmTool.deleteStudent(students: stus)
}
复制代码

删除后的数据库:

空空如也

文中所有演示代码 -> XWRealmSwiftDemo In Github

Swift-Realm数据库的使用详解的更多相关文章

  1. ASP.NET连接Oracle数据库的步骤详解(转)

    ASP.NET连接Oracle数据库的步骤详解   本文我们主要介绍了ASP.NET连接Oracle数据库的步骤及每个步骤需要进行的设置,希望能够对您有所帮助.   在用ASP.NET开发应用程序时, ...

  2. Net Core中数据库事务隔离详解——以Dapper和Mysql为例

    Net Core中数据库事务隔离详解--以Dapper和Mysql为例 事务隔离级别 准备工作 Read uncommitted 读未提交 Read committed 读取提交内容 Repeatab ...

  3. DB2创建数据库常用参数详解

    转自http://czmmiao.iteye.com/blog/1335801 DB2创建数据库常用参数详解 本文只介绍DB2 create database语法中的常用参数http://publib ...

  4. 重新学习MySQL数据库7:详解MyIsam与InnoDB引擎的锁实现

    重新学习Mysql数据库7:详解MyIsam与InnoDB引擎的锁实现 说到锁机制之前,先来看看Mysql的存储引擎,毕竟不同的引擎的锁机制也随着不同. 三类常见引擎: MyIsam :不支持事务,不 ...

  5. SqlServer数据库性能优化详解

    数据库性能优化详解 性能调节的目的是通过将网络流通.磁盘 I/O 和 CPU 时间减到最小,使每个查询的响应时间最短并最大限度地提高整个数据库服务器的吞吐量.为达到此目的,需要了解应用程序的需求和数据 ...

  6. Swift 中的Closures(闭包)详解

    Swift 中的Closures(闭包)详解 在Swift没有发布之前,所有人使用OC语言编写Cocoa上的程序,而其中经常被人们讨论的其中之一 -- Block 一直备受大家的喜爱.在Swift中, ...

  7. 数据库开发-pymysql详解

    数据库开发-pymysql详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Python支持的MySQL驱动 1>.什么是驱动 与MySQL通信就是典型的CS模式.Se ...

  8. Python操作SQLite数据库的方法详解

    Python操作SQLite数据库的方法详解 本文实例讲述了Python操作SQLite数据库的方法.分享给大家供大家参考,具体如下: SQLite简单介绍 SQLite数据库是一款非常小巧的嵌入式开 ...

  9. 【山外笔记-数据库】Memcached详解教程

    本文打印版文档下载地址 [山外笔记-数据库]Memcached详解教程-打印版.pdf 一.Memcached数据库概述 1.Memcached简介 (1)Memcached是一个自由开源的,高性能, ...

随机推荐

  1. 打造一款 刷Java 知识的小程序(一)

    一.为什么要打造 Java要学的东西太多了,所以准备把这些知识汇总到一起,而小程序是一个比较好的入口,借助微信客户端,打开方便. 二.打造成什么样 首页展示:包含了Java各大知识点模块 知识点展示: ...

  2. json的fromjson的方法使用。可以在volley中进行使用

    Gson提供了fromJson()方法来实现从Json相关对象到Java实体的方法. 在日常应用中,我们一般都会碰到两种情况,转成单一实体对象和转换成对象列表或者其他结构. 先来看第一种: 比如jso ...

  3. 一口气说出 4种 LBS “附近的人” 实现方式,面试官笑了

    引言 昨天一位公众号粉丝和我讨论了一道面试题,个人觉得比较有意义,这里整理了一下分享给大家,愿小伙伴们面试路上少踩坑.面试题目比较简单:"让你实现一个附近的人功能,你有什么方案?" ...

  4. 最全的中文NLP资源库,你确定不来看一下吗?

    最全的中文NLP资源库,你确定不来看一下吗? 22/100 发布文章 qq_39248703 hello,小伙伴们大家好,今天给大家分享NLP资源库,可以说是最全的资源库了,很多包非常有趣,值得收藏, ...

  5. C++语言实现双向链表

    这篇文章是关于利用C++模板的方式实现的双向链表以及双向链表的基本操作,在之前的博文C语言实现双向链表中,已经给大家分析了双向链表的结构,并以图示的方式给大家解释了双向链表的基本操作.本篇文章利用C+ ...

  6. 关于redis单线程的分析

    redis为什么那么快?结论有三点,大家都知道,这里主要是分析. 首先第一点 redis是内存访问的,所以快 当然这个大家都知道,所以不是重点 io密集型和cpu密集型 一般我们把任务分为io密集型和 ...

  7. "首字母变大写"组件:<capitalize> —— 快应用组件库H-UI

     <import name="capitalize" src="../Common/ui/h-ui/text/c_text_capitalize"> ...

  8. leetcode 703. Kth Largest Element in a Stream & c++ priority_queue & minHeap/maxHeap

    703. Kth Largest Element in a Stream & c++ priority_queue & minHeap/maxHeap 相关链接 leetcode c+ ...

  9. Python 操作mysql数据库之 SQLAlchemy 案例详解

      前言: 字段声明类型中,最右边的是数据库中对应的字段,我们依然可以使用,其左边的的 SQLAchemy 则是其自身封装的自定义类型. 本篇不会讲太多的理论知识,因为这个实用性更强,所以通篇全部都是 ...

  10. GeoGebra小制作

    效果 文件链接https://www.geogebra.org/m/bkxrjymh