iOS-Swift之Realm的使用教程

版本:Realm Swift 3.15.0

使用要求

  • Xcode9.2或更高版本
  • 目標平臺要iOS8或以上

安裝

有3種方式:Dynamic Framwork\CocoaPods\Carthage

我是用CocoaPods安裝的,說一下具體步驟。

  • 首先要先安裝CocoaPods(1.1.0以上版本)
  • 然後在終端運行$ pod repo update 讓 CocoaPods 更新realm的最新可用版本
  • 項目路徑下終端運行$ pod init 新建Podfile文件(若已經有就不用新建了)
  • 在Podfile文件添加 use_frameworks!  和 pod 'RealmSwift' 
  • 在終端運行pod install 進行安裝
  • 打開.xcworkspace結尾的文件以啓動工程

Models模型

Realm的Model類必須繼承Object。

屬性必須使用 @objc dynamic var 特性,從而讓其能夠訪問底層數據庫的數據。

有3個例外,LinkingObjects \ List \ RealmOptional。這些屬性不能聲明爲動態屬性,因爲泛型屬性無法在 Objective-C 運行時中正確表示,而這個運行時是用來對 dynamic 屬性進行動態調度的。這些屬性應當始終用 let 進行聲明。

import RealmSwift

class Person: Object {

    //屬性必須使用 @objc dynamic var 特性,從而讓其能夠訪問底層數據庫的數據。
    @objc dynamic var tmpID = 0
    @objc dynamic var id = 0
    @objc dynamic var name = ""
    @objc dynamic var picture: Data? = nil //支持可選類型
    let dogs = List<Dog>()
    
    //設置主鍵--聲明主鍵允許對象的查詢和更新更加高效,並且會強制要求每個值保持唯一性。
    //主鍵的值一旦寫入Realm便不能修改了
    override static func primaryKey() -> String? {
        return "id"
    }
    
    //設置索引屬性--會讓寫的操作稍微慢些, 但用equality和IN操作符查詢數據會更快.
    //最好在特殊的情況下使用索引屬性,譬如希望能提升讀取數據的速度的情況。
    override static func indexedProperties() -> [String] {
        return ["name"]
    }
    
    //設置忽略屬性--不會保存在Realm數據庫中
    //就像正常的屬性,但不支持使用任何realm中的功能,例如是查詢功能。但還是能通過KVO來觀察值的變化。 
    override static func ignoredProperties() -> [String] {
        return ["tmpID"]
    }
   
}

操作Realm對象

1)對象的自動更新

let person = Person()
person.name = "Fido"
mperson.age = 1

try! realm.write {
    realm.add(person)
}

let targetPerson = realm.objects(Person.self).filter("age == 1").first
try! realm.write {
    targetPerson!.age = 2
}

print("age of my dog: \(person.age)") // => 2

2)model類繼承

// Base Model
class Animal: Object {
    @objc dynamic var age = 0
}

// 與Animal類組合的models
class Duck: Object {
    @objc dynamic var animal: Animal? = nil
    @objc dynamic var name = ""
}
class Frog: Object {
    @objc dynamic var animal: Animal? = nil
    @objc dynamic var dateProp = Date()
}

// 使用
let duck = Duck(value: [ "animal": [ "age": 3 ], "name": "Gustav" ])

 

Writes寫

  • models: 
class Dog: Object {
    @objc dynamic var name = ""
    @objc dynamic var color = ""
    @objc dynamic var age = 0
    
}

class Human: Object {
    @objc dynamic var name = ""
    @objc dynamic var age = 0
    let dogs = List<Dog>()  
}
  • writes (寫操作需要在transaction中)
//方法1 - 通過Dog的屬性創建
let myDog = Dog()
myDog.name = "栗子"
myDog.color = "black"
myDog.age = 3
//方法2 - 通過字典創建
let myOtherDog = Dog(value: ["name":"happy","color":"white","age":1])
//方法3 - 通過數組創建
let myThirdDog = Dog(value: ["dogy","brown",3])
        
//利用存在的Dog Object創建
let aPerson = Human(value: ["James", 20, [myDog, myOtherDog]])
//直接創建
let anotherPerson = Human(value: ["Jane", 30, [["Buster","yellow", 5], ["Buddy","purple", 6]]])

// Write - 把數據寫進realm數據庫
try! realm.write {
     realm.add(myDog)
     realm.add(myOtherDog)
     realm.add(myThirdDog)
     realm.add(aPerson)
     realm.add(anotherPerson)           
}
  • 結果(通過Realm Browser查看,可以App Store直接下載):

 

Queries查詢

  • 查詢整個表格(因爲realm中的查詢都是懶加載的,只有在訪問屬性時纔讀取數據,所以不用擔心會佔用太多內存)
//查詢整個Human表格 --> Results<Human>
let persons = realm.objects(Human.self)
  • 通過filter查詢 
//通過filter查詢1 --> Results<Dog>
let puppies = realm.objects(Dog.self).filter("age < 3")

//通過filter查詢2 --> Results<Dog>
let targetDogs = realm.objects(Dog.self).filter("age = 2 AND name BEGINSWITH '慄'")
  • 通過NSPredicate查詢 
//通過NSPredicate查詢 --> Results<Human>
let predicate = NSPredicate(format: "age = 23 AND name BEGINSWITH %@", "J")
let targetHuman = realm.objects(Human.self).filter(predicate)

 

Update更新 (更新操作需要在transaction中)

  • 可在任何線程查詢或更新
//可在任何線程查詢或更新
DispatchQueue(label: "background").async {
    autoreleasepool {
        let realm = try! Realm()
        let persons = realm.objects(Human.self)
        try! realm.write {
            //把name這列數據的第一個James更新爲James blunt(KeyPath是model中的變量)
            persons.first?.setValue("James blunt", forKeyPath: "name")
            //把age這列數據全部更新爲23
            persons.setValue(23, forKeyPath: "age")

        }
    }
}
  • 有主鍵的model可直接更新 

let animal = Animal(value: [1,"elephant"])
try! realm.write {     
     //有主鍵的object可直接更新
     realm.add(animal, update: true)
}

 

Delete刪除

  • 刪除指定數據
let animal = Animal(value: [1,"elephant"])
try? realm.write {
     realm.delete(animal)
}
  • 刪除所有
try! realm.write {
     realm.deleteAll()
}

Migration數據遷移

  • 當你想更新數據模型,例如在模型Animal類中新增屬性age(原本只有id和name兩個屬性)。不僅要在model類中增加屬性,還要進行migration操作。
class Animal: Object {
    @objc dynamic var id = 0
    @objc dynamic var name = ""
    @objc dynamic var age = 0

}
  • migration操作 - 在AppDelegate.swift中的 didFinishLaunchingWithOptions 函數中操作。要更新數據模型時增加下面的版本號即可。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    let config = Realm.Configuration(
        // 設置新的圖表版本. 一定要比之前的版本號要大,默認版本號是0.
        schemaVersion: 1,
            
        // 當打開低於上面版本realm數據庫時會自動調用這個遷移閉包
        migrationBlock: { migration, oldSchemaVersion in
    
        if (oldSchemaVersion < 1) {
             // 不用做任何事,Realm會檢測新的屬性和移除舊的屬性,然後自動更新數據庫。
        }
    })
        
    // 使默認Realm使用新的配置
    Realm.Configuration.defaultConfiguration = config

    return true
}

 

參考自最新官方文檔:https://realm.io/docs/swift/latest/

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章