概述
Realm 是一個跨平臺的移動數據庫引擎,其性能要優于 Core Data 和 FMDB - 移動端數據庫性能比較, 我們可以在 Android 端 realm-java,iOS端:Realm-Cocoa,同時支持 OC 和 Swift兩種語言開發。其使用簡單,免費,性能優異,跨平臺的特點廣受程序員GG喜愛。
本文將結合一些實戰演練講解 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 類的子類。
- 設置主鍵 - primaryKey
重寫 Object.primaryKey() 可以設置模型的主鍵。
聲明主鍵之后,對象將被允許查詢,更新速度更加高效,并且要求每個對象保持唯一性。
一旦帶有主鍵的對象被添加到 Realm 之后,該對象的主鍵將不可修改。
override static func primaryKey() -> String? {
return "id"
}
- 忽略屬性 - 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
}