首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Realm Swift 核心功能完整指南:從數據建模到線程同步

     編輯:Java 綜合教學

Realm Swift 核心功能完整指南

Realm 是一款專為移動端設計的高性能數據庫框架,其 Swift 版本提供了類型安全、響應式的數據持久化方案。本文系統梳理 Realm Swift 的核心特性,涵蓋數據建模、關聯關係、查詢優化、線程處理等關鍵技術點,幫助開發者快速掌握最佳實踐。

支援的數據類型

Realm Swift 原生支援以下基礎類型:

  • 字符串類型:String、NSString
  • 整數類型:Int、Int8、Int16、Int32、Int64
  • 浮點類型:Float、Double
  • 布爾類型:Bool
  • 二進制與日期:NSData、NSDate
  • 特殊包裝類型:RealmOptional、Object、List

物件模型定義

所有模型類必須繼承 Object,屬性聲明需遵循特定規範:

class Dog: Object {
    dynamic var name = ""
    dynamic var age = 0
    let owner = LinkingObjects(fromType: Person.self, property: "dogs")
}

屬性聲明規範表

類型非可選聲明可選聲明
Booldynamic var value = falselet value = RealmOptional<Bool>()
Intdynamic var value = 0let value = RealmOptional<Int>()
Stringdynamic var value = ""dynamic var value: String? = nil
Object不支援dynamic var value: Class?
Listlet value = List<Type>()必須非可選

關鍵規則: Object 僅能聲明為可選;List 和 RealmOptional 必須非可選;所有 var 屬性必須標註 dynamic。

關聯關係建模

一對一關係

class Dog: Object {
    dynamic var owner: Person?  // 必須可選
}

一對多關係

class Person: Object {
    let dogs = List<Dog>()
}

反向關聯

class Dog: Object {
    var owners: [Person] {
        return linkingObjects(Person.self, forProperty: "dogs")
    }
}

索引優化策略

透過重寫 indexedProperties() 為頻繁查詢的屬性添加索引:

class Book: Object {
    dynamic var price = 0
    dynamic var title = ""
    
    override static func indexedProperties() -> [String] {
        return ["title"]
    }
}

支援索引的類型:字符串、整數、布爾值、NSDate。權衡: 索引大幅提升等值查詢(=、IN)速度,但會降低插入性能。

自動更新機制

Realm 物件具備即時更新特性:

let myDog = Dog()
myDog.name = "Fido"
myDog.age = 1
try! realm.write { realm.add(myDog) }

let myPuppy = realm.objects(Dog).filter("age == 1").first
try! realm.write { myPuppy!.age = 2 }
print("age of my dog: \(myDog.age)") // 輸出 2

配合 Realm Notifications 或 KVO 可實現 UI 自動刷新。

主鍵與忽略屬性

class Person: Object {
    dynamic var id = 0
    dynamic var name = ""
    dynamic var tmpID = 0
    
    override static func primaryKey() -> String? {
        return "id"
    }
    
    override static func ignoredProperties() -> [String] {
        return ["tmpID"]
    }
    
    var fullName: String {
        return "\(firstName) \(lastName)"  // 唯讀屬性自動忽略
    }
}

主鍵一旦寫入不可修改,且隱含唯一性約束。

寫入事務管理

所有寫操作(增、刪、改)必須在 write transaction 中執行。 為減少資源佔用,應合併事務、避免頻繁提交。

物件創建方式

// 方式一:逐屬性賦值
var myDog = Dog()
myDog.name = "Rex"
myDog.age = 10

// 方式二:字典初始化
let myOtherDog = Dog(value: ["name": "Pluto", "age": 3])

// 方式三:數組初始化
let myThirdDog = Dog(value: ["Fido", 5])

巢狀物件創建

let anotherPerson = Person(value: ["Jane", 30, [["Buster", 5], ["Buddy", 6]]])

主鍵更新策略

try! realm.write {
    realm.add(cheeseBook, update: true)  // 需主鍵存在
    realm.create(Book.self, value: ["id": 1, "price": 9000.0], update: true)
}

查詢系統深度解析

Realm 查詢返回 Results 集合,特性如下:

  • 行為類似 Array,支援下標訪問
  • 惰性加載:僅在屬性訪問時讀取數據
  • 返回引用而非拷貝,寫入事務中修改即同步到數據庫

條件過濾

// 字符串 predicate
var tanDogs = realm.objects(Dog).filter("color = 'tan' AND name BEGINSWITH 'B'")

// NSPredicate
let predicate = NSPredicate(format: "color = %@ AND name BEGINSWITH %@", "tan", "B")
tanDogs = realm.objects(Dog).filter(predicate)

// 鏈式過濾
tanDogs = realm.objects(Dog).filter("color = 'tan'").filter("name BEGINSWITH 'B'")

支援的運算符

  • 比較:==、<=、<、>=、>、!=、BETWEEN(數值、日期)
  • 字符串:==、!=、BEGINSWITH、CONTAINS、ENDSWITH,支援 [c] 忽略大小寫
  • 邏輯:AND、OR、NOT
  • 集合:IN、ANY
  • 聚合:@count、@min、@max、@sum、@avg

排序與分頁

let sortedDogs = realm.objects(Dog)
    .filter("color = 'tan' AND name BEGINSWITH 'B'")
    .sorted("name", ascending: false)

// 限制結果數量(惰性加載無需 LIMIT)
let dogs = try! Realm().objects(Dog)
for i in 0..<5 { let dog = dogs[i] }

Realm 配置與多實例管理

默認配置切換

func setDefaultRealmForUser(username: String) {
    var config = Realm.Configuration()
    config.path = NSURL.fileURLWithPath(config.path!)
        .URLByDeletingLastPathComponent?
        .URLByAppendingPathComponent("\(username).realm")
        .path
    Realm.Configuration.defaultConfiguration = config
}

唯讀 Bundle 數據

let config = Realm.Configuration(
    path: NSBundle.mainBundle().pathForResource("MyBundledData", ofType: "realm"),
    readOnly: true
)
let realm = try! Realm(configuration: config)

內存數據庫

適用於臨時數據、測試場景,無磁盤 I/O 開銷。注意: 必須保持強引用防止 ARC 回收。

線程同步最佳實踐

核心原則: 不能跨線程共享 Realm、Object、Results、List 實例。

跨線程傳遞方案

  • Object:透過主鍵重新查詢
  • Results:重新構建 filter/NSPredicate

線程隔離視圖機制

  • UI/RunLoop 線程:自動刷新(除非 autorefresh = false)
  • 後台線程:基於最後提交的快照,需手動 refresh()
  • commitWrite() 會觸發一次刷新

大量寫入優化範例

let queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT)
dispatch_async(queue) {
    autoreleasepool {
        let realm = try! Realm()
        for idx1 in 0..<1000 {
            realm.beginWrite()
            for idx2 in 0..<1000 {
                realm.create(Person.self, value: [
                    "name": "\(idx1)",
                    "birthdate": NSDate(timeIntervalSince1970: NSTimeInterval(idx2))
                ])
            }
            try! realm.commitWrite()
        }
    }
}

JSON 數據導入

不支援直接導入,需先轉換:

try! realm.write {
    let json = try! NSJSONSerialization.JSONObjectWithData(data, options: [])
    realm.create(City.self, value: json, update: true)
}

注意事項: Float 需用 NSNumber;NSDate/NSData 需預先轉換;JSON null 會導致必填字段異常;未定義屬性會被忽略。

通知機制

支援 Realm、Results、List、AnyRealmCollection 級別通知,Token 必須強引用持有:

let token = realm.addNotificationBlock { notification, realm in
    viewController.updateUI()
}
token.stop()

數據遷移策略

Schema 版本升級時必須提供遷移塊:

Realm.Configuration.defaultConfiguration.schemaVersion = 2
Realm.Configuration.defaultConfiguration.migrationBlock = { migration, oldSchemaVersion in
    if oldSchemaVersion < 1 {
        migration.enumerate(Person.className()) { oldObject, newObject in
            let firstName = oldObject!["firstName"] as! String
            let lastName = oldObject!["lastName"] as! String
            newObject!["fullName"] = "\(firstName) \(lastName)"
        }
    }
    if oldSchemaVersion < 2 {
        newObject!["email"] = ""
    }
}

線性遷移原則: 需處理跨版本升級(如 v0→v3),而非僅相鄰版本。

數據加密

支援 AES-256 + SHA2(64 字節密鑰),性能損耗 <10%。加密後無法用 Realm Browser 查看,每次開啟需提供 encryptionKey。密鑰建議存儲於 Keychain。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved