移動(dòng)開發(fā)數(shù)據(jù)庫(kù)篇 之 SwiftRealm(上)
@author fharmony Email Weibo or Github
Realm is a mobile database
hundreds of millions of people rely on .
1. 為什么要使用SwiftRealm?
新型數(shù)據(jù)庫(kù)白粉,同類型三方庫(kù)有CoreData
和SQLite
特點(diǎn):簡(jiǎn)單怒竿、快铅祸、文檔規(guī)范咐容、免費(fèi)
需要:iOS 8.0+(指的是Swift版本)
需要繼承Object
毫缆,具有一定程度的侵入性重绷。和AVOS Object類似银酗。但是需要注意的是慎框,如果使用的話realm是存儲(chǔ)在本地的數(shù)據(jù)良狈,和AVOS Object存儲(chǔ)在云端的數(shù)據(jù)作用不一樣。
快速集成
使用Cocoapods快速集成笨枯,請(qǐng)參考這個(gè)文章
podfile內(nèi)容:
platform :ios,'8.0'
use_frameworks!
target '<#你的TargetName#>' do
pod 'RealmSwift'
end
2. 數(shù)據(jù)模型 - 關(guān)系
數(shù)據(jù)模型的創(chuàng)建
可以使用Realm提供的Realm Model
創(chuàng)建薪丁,文件需要滿足:
- 指定數(shù)據(jù)類型或者是List類型
- 一定需要初始化
數(shù)據(jù)模型的關(guān)系
- 一對(duì)一關(guān)系 可以為空
-
一對(duì)多關(guān)系 通過(guò)List完成,提供了
List
類來(lái)作為列表 - 反向關(guān)系 可以通過(guò)一個(gè)特定的屬性獲取和給定對(duì)象有關(guān)系的所有對(duì)象馅精。即「具有XX屬性的那些對(duì)象」
數(shù)據(jù)類型:
常用類型:Bool\Double\Float\String\NSDate\NSData\Int32\Object
可選與不可選類型:
* 對(duì)于基本類型來(lái)說(shuō):
let style = RealmOptional<Int32>() --> 可選值
dynamic var style = 32 --> 不可選值
* 對(duì)對(duì)象類型來(lái)說(shuō)
let var value:Stirng? = nil --> 可選值
dynamic var value = ""
為什么使用dynamic严嗜?因?yàn)閞ealm工作基于OC運(yùn)行時(shí)。
為什么不使用計(jì)算屬性洲敢?計(jì)算屬性將不會(huì)被存儲(chǔ)到realm里面
索引屬性
重寫Object.indexedProperties()
添加索引屬性漫玄,支持用字符串、整數(shù)沦疾、布爾值称近、NSDate
作為索引,有利于提高檢索效率哮塞。
主鍵
重寫Object.primaryKey()
添加主鍵刨秆,主鍵不可修改而且能讓查詢更加高效。注意數(shù)據(jù)庫(kù)的主鍵是條目的唯一標(biāo)示忆畅,如果有兩條主鍵相同的條目衡未,那么后來(lái)的條目會(huì)更新前一個(gè)條目的數(shù)據(jù)。
忽略屬性
重寫 Object.ignoredProperties()
可以忽略 Realm 存儲(chǔ)數(shù)據(jù)模型的某個(gè)屬性家凯。
3.對(duì)數(shù)據(jù)庫(kù)的操作
對(duì)象存儲(chǔ)
對(duì)對(duì)象存儲(chǔ)的更改需要通過(guò)寫入事務(wù)write閉包
完成缓醋。
如果您想要在多個(gè)線程中共享對(duì)象,或者在應(yīng)用重啟后重復(fù)使用對(duì)象绊诲,那么您必須將其存儲(chǔ)到Realm數(shù)據(jù)庫(kù)中——這個(gè)操作必須在寫入事務(wù)中完成送粱。
寫入事務(wù)可能會(huì)失敗,所以需要添加throws標(biāo)記處理異常
- 增刪改
let realm = try! Realm()//建立realm數(shù)據(jù)庫(kù)
try! realm.write{
realm.add(object)//插入新對(duì)象
object.name = "new value"http://更新數(shù)值
realm.add(object,update:true)//對(duì)已經(jīng)存在的值進(jìn)行更新操作掂之,或者是對(duì)不存在的值進(jìn)行寫入抗俄,是否存在依據(jù)的是主鍵
realm.delete(object)//刪除對(duì)象
}
* 查
返回Results實(shí)例,查詢得到的是數(shù)據(jù)庫(kù)里面的數(shù)據(jù)世舰,在寫入操作的時(shí)候可以修改數(shù)據(jù)庫(kù)的數(shù)據(jù)动雹。您可以將 Results 存儲(chǔ)為一個(gè)屬性,這樣就無(wú)需在每次訪問(wèn)前都要刷新數(shù)據(jù)以確保數(shù)據(jù)最新了跟压。realm的查詢?cè)试S鏈?zhǔn)讲樵儭?/p>
let dogs = realm.Objects(Dog)
let tanDogs = realm.Objects(Dog).filter("NSPredicate斷言")
- 排序
根據(jù)某個(gè)屬性進(jìn)行排序
let sortedDogs = realm.objects(Dog).filter("color = '棕黃色' AND name BEGINSWITH 'B'").sorted("color")
創(chuàng)建對(duì)象
var myDog = Dog()
和swift新建對(duì)象的方法一致
創(chuàng)建數(shù)據(jù)庫(kù)
通過(guò)調(diào)用 Realm()會(huì)在應(yīng)用文件夾下的一個(gè)名為“default.realm”的文件胰蝠,realm.path
來(lái)獲取realm數(shù)據(jù)庫(kù)地址,可以使用Realm Browser
進(jìn)行查看
配置realm
通過(guò)Realm.Configuration您可以配置諸如 Realm 文件在何處存儲(chǔ)之類的信息。蘋果推薦<Application_Home>/Library/Caches目錄下茸塞,
在生成 Realm 文件的代碼處躲庄,您需要結(jié)尾對(duì)文件進(jìn)行壓縮拷貝(參見 Realm().writeCopyToPath(_:encryptionKey:))。 這有助于減少 Realm 的文件體積翔横,讓您發(fā)布的應(yīng)用體積更卸刘巍;
刪除數(shù)據(jù)庫(kù)
大多數(shù)文件可以通過(guò)removeItemAtPath刪除禾唁,但是您必須要采取額外的操作效览,來(lái)確保沒(méi)有任何活躍的 Realm 對(duì)象在刪除過(guò)程中訪問(wèn)數(shù)據(jù)庫(kù)。Realm 實(shí)例將會(huì)在它們的整個(gè)生命周期中荡短,持有對(duì)數(shù)據(jù)庫(kù)的連接丐枉。限制 Realm 實(shí)例生命周期的方法就是使用 autorelease pool 將其使用操作包含在其中。所有 path 指向您想要?jiǎng)h除的 Realm 文件的 Realm 實(shí)例掘托,都必須要在刪除操作執(zhí)行前被釋放掉瘦锹。
4. 多線程
Realm 通過(guò)確保每個(gè)線程始終擁有 Realm 的一個(gè)快照,以便讓并發(fā)運(yùn)行變得十分輕松闪盔。您唯一需要注意的一件事情就是不能讓多個(gè)線程都持有同一個(gè) Realm 對(duì)象的 實(shí)例 弯院。如果定期刷新 Realm 失敗的話,就可能會(huì)導(dǎo)致某些事務(wù)的版本變?yōu)椤版i定(pinned)”狀態(tài)泪掀,阻止 Realm 重用該版本的硬盤空間听绳,從而導(dǎo)致文件尺寸變大。
不支持 跨線程共享Realm 實(shí)例异赫。 Realm 實(shí)例要訪問(wèn)相同的 Realm 文件還必須使用相同的 Realm.Configuration椅挣。
當(dāng)你同時(shí)進(jìn)行多個(gè)寫操作的時(shí)候,他們會(huì)相互阻塞塔拳,阻塞住他們所運(yùn)行的線程鼠证。因此您必須要為每一個(gè)您想要執(zhí)行讀取或者寫入操作的線程或者dispatch隊(duì)列創(chuàng)建一個(gè) Realm 實(shí)例。所以應(yīng)當(dāng)考慮在 UI 之外的線程中來(lái)進(jìn)行操作靠抑。另外需要注意的是量九,在進(jìn)行寫事務(wù)的時(shí)候,讀操作并不會(huì)造成阻塞颂碧。這非常有用荠列,尤其是當(dāng)你在后臺(tái)進(jìn)行寫操作的時(shí)候,用戶可能會(huì)在不同界面切換稚伍,而這時(shí)候可以進(jìn)行讀操作
Realm 對(duì)象在每個(gè)線程中都應(yīng)該只被創(chuàng)建一次弯予,因?yàn)樗皇蔷€程安全的戚宦,不能在不同的線程中共享个曙。如果你想要在另一個(gè)線程中執(zhí)行寫操作,那么就需要?jiǎng)?chuàng)建一個(gè)新的 Realm 對(duì)象。
建議你使用常用的垦搬,也是最有效的方案呼寸, 將所有寫入放到一個(gè)單獨(dú)的進(jìn)程中。
5. 其他
通知
通過(guò)調(diào)用 addNotificationBlock 方法進(jìn)行通知注冊(cè)后猴贰,無(wú)論哪個(gè) Realm, Results 或者 List 對(duì)象更新对雪,都可以得到通知。Results 以及 List 實(shí)例在注冊(cè)的時(shí)候米绕,會(huì)使用初始的集合來(lái)調(diào)用閉包瑟捣,然后當(dāng)每次寫事務(wù)對(duì)集合或者包含在其中的任何事物進(jìn)行改變之后,會(huì)再次調(diào)用一遍此閉包栅干。
加密
- 在iOS平臺(tái)中迈套,通過(guò)使用 NSFileProtection API 就可以花費(fèi)極小的代價(jià)完成 Realm 的文件加密。
- 使用realm官方的加密方法:
// 產(chǎn)生隨機(jī)密鑰
let key = NSMutableData(length: 64)!
SecRandomCopyBytes(kSecRandomDefault, key.length,
UnsafeMutablePointer<UInt8>(key.mutableBytes))
// 打開加密文件
let config = Realm.Configuration(encryptionKey: key)
do {
let realm = try Realm(configuration: config)
// 和往常一樣使用 Realm 即可
let dogs = realm.objects(Dog).filter("name contains 'Fido'")
} catch let error as NSError {
// 如果密鑰錯(cuò)誤碱鳞,`error` 會(huì)提示數(shù)據(jù)庫(kù)不可訪問(wèn)
fatalError("Error opening realm: \(error)")
}
參考資料
—— 念念不忘桑李,必有回響