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)
Realm 安裝 - 使用 CocoaPods

pod 'RealmSwift'
pod 'Realm'

Realm 配置
  • 在 AppDelegate 的 didFinishLaunchingWithOptions 方法中調用以下方法,這個方法主要用于數據模型屬性增加或刪除時的數據遷移,每次模型屬性變化時,將 dbVersion 加 1 即可,Realm 會自行檢測新增和需要移除的屬性,然后自動更新硬盤上的數據庫架構,移除屬性的數據將會被刪除。
///配置數據庫
   RealmHelper.configRealm()

configRealm方法說明如下

    ///  配置數據庫
    public class func configRealm() {
        /// 這個方法主要用于數據模型屬性增加或刪除時的數據遷移,每次模型屬性變化時,將 dbVersion 加 1 即可,Realm 會自行檢測新增和需要移除的屬性,然后自動更新硬盤上的數據庫架構,移除屬性的數據將會被刪除。
        let dbVersion : UInt64 = 1
        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
import Realm

class Book: Object {
    @objc dynamic var name = ""
    @objc dynamic var author = ""
    
    convenience init(name : String,author : String) {
          self.init();
          self.name = name;
          self.author = 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"
    }
  1. 忽略屬性 - 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 ,因為在 Objective-C 運行時無法表示泛型屬性。
注意: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.增

    ///新增單條數據
    public class func addObject<T>(object: T){
        
        do {
            let defaultRealm = self.getDB()
            try defaultRealm.write {
                defaultRealm.add(object as! Object)
            }
            print(defaultRealm.configuration.fileURL ?? "")
        } catch {}
        
    }
        
    /// 保存多條數據
    public class func addObjects<T>(by objects : [T]) -> Void {
        let defaultRealm = self.getDB()
        try! defaultRealm.write {
            defaultRealm.add(objects as! [Object])
        }
        print(defaultRealm.configuration.fileURL ?? "")
    }

2.刪

    /// 刪除單條
    /// - Parameter object: 刪除數據對象
    public class func deleteObject<T>(object: T?) {
        
        if object == nil {
            print("無此數據")
            return
        }
        
        do {
              let defaultRealm = self.getDB()
              try defaultRealm.write {
                  defaultRealm.delete(object as! Object)
              }
        } catch {}
    }
    
    
    /// 刪除多條數據
    /// - Parameter objects: 對象數組
    public class func deleteObjects<T>(objects: [T]?) {
        
        if objects?.count == 0 {
            print("無此數據")
            return
        }
        
        do {
              let defaultRealm = self.getDB()
              try defaultRealm.write {
                  defaultRealm.delete(objects as! [Object])
              }
        } catch {}
    }

    
    /// 根據條件去刪除單條/多條數據
    public class func deleteObjectFilter<T>(objectClass: T, filter: String?) {
        
        let objects = RealmHelper.queryObject(objectClass: objectClass, filter: filter)
        RealmHelper.deleteObjects(objects: objects)
        
    }
    
   
    /// 刪除某張表
    /// - Parameter objectClass: 刪除對象
      public class func clearTableClass<T>(objectClass: T) {
          
          do {
                let defaultRealm = self.getDB()
                try defaultRealm.write {
                    defaultRealm.delete(defaultRealm.objects((T.self as! Object.Type).self))
                }
          } catch {}
      }

3.更新

///更新單條數據
    public class func updateObject<T>(object: T) {
        
        do {
            let defaultRealm = self.getDB()
            try defaultRealm.write {
                defaultRealm.add(object as! Object, update: .error)
            }
        }catch{}
    }
    
    
    
    /// 更新多條數據
    public class func updateObjects<T>(objects : [T]) {
        let defaultRealm = self.getDB()
        try! defaultRealm.write {
            defaultRealm.add(objects as! [Object], update: .error)
        }
    }
    
    /// 更新多條數據的某一個屬性
    public class func updateObjectsAttribute<T>(objectClass : T ,attribute:[String:Any]) {
        let defaultRealm = self.getDB()
        try! defaultRealm.write {
            let objects = defaultRealm.objects((T.self as! Object.Type).self)
            let keys = attribute.keys
             for keyString in keys {
                objects.setValue(attribute[keyString], forKey: keyString)
            }
        }
    }

4.查詢

/// 查詢數據
    /// - Parameters:
    ///   - objectClass: 當前查詢對象
    ///   - filter: 查詢條件
    class func queryObject <T> (objectClass: T, filter: String? = nil) -> [T]{
        
        let defaultRealm = self.getDB()
        var results : Results<Object>
        
        if filter != nil {
                 
            results =  defaultRealm.objects((T.self as! Object.Type).self).filter(filter!)
        }
        else {
                 
            results = defaultRealm.objects((T.self as! Object.Type).self)
        }
        
        guard results.count > 0 else { return [] }
        var objectArray = [T]()
        for model in results{
           objectArray.append(model as! T)
        }
       
        return objectArray
        
    }

注:

通過 Realm Browser 查看剛才保存的數據

通過 print(realm.configuration.fileURL ?? "") 打印數據路徑

以下提供Demo地址

Demo下載地址

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容