zoukankan      html  css  js  c++  java
  • Swift-Realm数据库的使用详解

    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

  • 相关阅读:
    codeforces 814B An express train to reveries
    codeforces 814A An abandoned sentiment from past
    codeforces 785D D. Anton and School
    codeforces 785C Anton and Fairy Tale
    codeforces 791C Bear and Different Names
    AOP详解
    Spring集成JUnit测试
    Spring整合web开发
    IOC装配Bean(注解方式)
    IOC装配Bean(XML方式)
  • 原文地址:https://www.cnblogs.com/twodog/p/12136777.html
Copyright © 2011-2022 走看看