Realm的常規(guī)使用與線程中的坑

結識 Realm 的催化劑

? ? ? ?在我們公司的項目迭代中,由于在之前的聊天這個模塊關于用戶信息的傳值有問題,而之前因為項目經過很多開發(fā)者的手,且不提整體的架構有多混亂,就單說緩存這塊,就是亂的不行,有的地方用CoreData,有的地方用FMDB, 而且封裝的Manager中方法的聲明很亂,存取的邏輯也不是很清晰,于是造成了很多我需要取到數(shù)據(jù)的時候,根本取不到,而當我修改大部分本次版本迭代的需求時,發(fā)現(xiàn)這個取不到值問題如果繼續(xù)沿用之前的邏輯就會非常的麻煩,我要用很多額外方法去跳過之前的坑,只是我決定,在群組聊天的功能中,將用戶數(shù)據(jù)的傳值這塊邏輯重構. ? ??

? ? ? ? 傳值的邏輯還是比較好重構的,我將原有用在這里的 CoreData代碼全部都清掉,讓整體功能即使不依賴于緩存,依舊可以正確及時的取到需要的數(shù)據(jù),只是需要等待服務器的響應,但是如果每次都去走服務端的網絡請求,那么體驗就太差了,那么緩存便是很重要的一步.

? ? ? ? 之前說過,現(xiàn)有項目有,有的地方采用了 CoreData,有的用了 FMDB,十分混亂,而我們的用戶量還并涉及不到數(shù)據(jù)遷移的問題.所以我想采用另一套緩存框架來完成我的需求,那么我第一個想到的就是 Realm.

初識 Realm

? ? ? ? Realm是一個跨平臺的移動數(shù)據(jù)庫引擎,而且,它是專門為移動端數(shù)據(jù)應用設計的數(shù)據(jù)持久化方案.不論是 CoreData,還是傳統(tǒng)的SQLite,代碼都些許冗余.CoreData的笨拙的API和FMDB相對不那么面向對象的操作方式,可能會很多人望而卻步或萌生停用的念頭,那么這個時候,Realm 出現(xiàn)了.

? ? ? Realm既不是 CoreData,也不是SQLite,它擁有自己的數(shù)據(jù)庫存取引擎,它可以跨平臺使用,也意味著更加快速的存取速度,官方給出的Realm的存取速度比 CoreData快了3倍,但是據(jù)說在實際使用中,當數(shù)據(jù)量很大時候,Realm的速度比 CoreData 快了不值30倍.

? ? ? 說了這么多,你一定對 Realm 也有了些許好感,這篇文章中我并打算介紹關于 Realm 的使用方法,因為文檔Relam的官方文檔中寫的清清楚楚,網上很多大神也做了相關介紹,但是大多數(shù)的博客中方法的介紹都是局限在了 Demo 的使用中,真的作用于項目的很少,我在此也算賣弄賣弄我在植入到實際項目時所遇到的小坑或者經驗吧.

??1.由于 RLMArray 的關系,這句話一定要寫,來定義 RLMArray 中的實例,不然會崩潰

? ?2.由于數(shù)據(jù)模型已經由繼承與 NSObject 的 Model, 改為了繼承于 RLMObject,所以在使用 KVC 的時候一定要注意.

3.主鍵

如果你想要更新數(shù)據(jù),主鍵是不錯的選擇

4.線程

? ? ? ?線程問題的坑是我這篇文章所要說的重點.其實 Realm 在關于線程的處理上已經幫我們做了很多事情,我自己并不需要講過多的精力放在線程上,但是 Realm 本身的線程管理非常嚴格,所以我們必須遵守Realm 的使用方式,這就使得坑與有點并存

? ? ? ? 原本我最開始關于緩存的設計思路是,我從服務端拿到了數(shù)據(jù),那么我會把數(shù)據(jù)放入內存中的數(shù)組容器中,再存入數(shù)據(jù)庫中,那么下次進入這個頁面我就可以先從數(shù)據(jù)庫中拿到數(shù)據(jù)后放入容器,再通過服務端進行更新,也是說在當前 Controller 中,我只需要通過數(shù)組容器進行賦值就可以了.然而 Realm 并不允許你這樣,當我將數(shù)據(jù)存入 Realm 后,我還沒有進行取數(shù)據(jù)的操作,我只是用數(shù)據(jù)容器,但這時,程序崩潰了, WTF????!!!! 查看一下崩潰信息 Realm accessed from incorrect thread(從錯誤的線程訪問),當時我就委屈了,我存的時候沒有崩潰,也沒取啊,怎么就崩潰的,后來我又不得已的用蹩腳的英語水平仔細研讀了一下原文文檔.

蛋疼的開始

同一個 Realm提交過寫入就可以在其他線程被各種蹂躪
Realm的實例不是安全線程的不能在其他線程或列隊被訪問

臥槽???看的我是萬臉懵逼!!

? ? ? ?于是我就交了個 Realm的技術交流群,開始,還有人跟我交流交流使用心德,等把把圖貼出來,石沉大海一般,可能是兩張截圖暴露我的智商和理解能力,大家不想跟差生玩兒...好吧,本著 API 文檔就像游戲攻略一樣的原則,看不懂的,就帶著疑問去玩一玩...那么既然增沒事兒,改刪查也都沒做,那問題會不會出現(xiàn)在了 RLMObject 的調用上,于是在遍歷使用之前說的數(shù)組容器的地方,打印了當前線程,嗯,果然不是主線程,那既然說同一個 Realm 只要提交了寫入就可以在其他線程改變,那我于是試了試 [RLMObject ?objectWhere:@"查詢條件"],發(fā)現(xiàn)就完全沒有問題的,那原因到底是什么呢?于是我又開始啃文檔

你可以有任意數(shù)量的線程并行工作在同一個Realm
只是唯一要注意的是你不能在多個線程共享同一個 RealmObject實例

? ? ? ? 這就非常清晰了, Realm 本身在工程中的調用也是個單例類[RLMRealm defaultRealm],所以只要是同一個 Realm, 就可以在任意線程,哪怕是多個線程中,隨意使用,不需要鎖,只需要將 commitWriteTransaction就可以.但是 RLMObject 的使用的限制就非常嚴格的,主線程里創(chuàng)建的 RLMObject 就只能在主線程里用,在其他線程中調用的這個它的實例就會拋出異常,有人說,這是 Realm的線程坑,但是我覺得這個是 Realm 對線程做的最好的處理

為此我特意寫了一段非常欠打的代碼,來驗證 Realm 是如何處理并發(fā)問題的



#pragma mark 這是第一個子線程? 這里面進行更新寫入

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

NSLog(@"current ======= %@",[NSThread currentThread]);

for (int i = 0; i < 35; i ++) {

InformationUpdateModel *model = [[InformationUpdateModel alloc] init];

model.name = [NSString stringWithFormat:@"草鞋%d號",i];

model.age = i;

RLMRealm *relam = [RLMRealm defaultRealm];

[relam transactionWithBlock:^{

[relam addOrUpdateObject:model];

[relam commitWriteTransaction];

}];

}

dispatch_async(dispatch_get_main_queue(), ^{

[InfomationModel allObjects];

});

});

#pragma mark 這是第二個子線程? 這里面是查詢

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

NSLog(@"current ======= %@",[NSThread currentThread]);

[InfomationModel allObjects];

});

#pragma mark 這里是第三個子線程? 這里是更新寫入加查詢? 回到主線程后繼續(xù)更新寫入加查詢

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

NSLog(@"current ======= %@",[NSThread currentThread]);

for (int i = 60; i < 80; i ++) {

InformationUpdateModel *model = [[InformationUpdateModel alloc] init];

model.name = [NSString stringWithFormat:@"草鞋%d號",i];

model.age = i;

RLMRealm *relam = [RLMRealm defaultRealm];

[relam transactionWithBlock:^{

[relam addOrUpdateObject:model];

[relam commitWriteTransaction];

}];

}

[InfomationModel allObjects];

dispatch_async(dispatch_get_main_queue(), ^{

for (int i = 40; i < 50; i ++) {

InformationUpdateModel *model = [[InformationUpdateModel alloc] init];

model.name = [NSString stringWithFormat:@"草鞋%d號",i];

model.age = i;

RLMRealm *relam = [RLMRealm defaultRealm];

[relam transactionWithBlock:^{

[relam addOrUpdateObject:model];

[relam commitWriteTransaction];

}];

}

});

});

我直接開了三個子線程,并在其中用同一個 Realm 各自存取

三個子線程

從時間上來看,形成了一個小規(guī)模的并發(fā),也是說,會在Realm可能同時即被讀,又被寫,但是完全沒有報出異常,程序流暢運行,數(shù)據(jù)也沒有出現(xiàn)錯誤.

由于MVCC 架構,不會阻塞讀寫

關于 Realm 就先說到這里,其實 Realm 也有很多不便之處,比如我們的模型必須要繼承RLMObject,他的RLMArray也并不是 NSArray類型,所以從代碼的獨立性角度上來說,就不是特別的完美,如果本身項目中有一套完整嚴格的數(shù)據(jù)協(xié)議,那么 Realm 可能就不會是一個好的選擇,而且本身自帶 Model,也被很多架構師的去 Model 化思想想違背,但這并不妨礙它是一套專門用于移動端,速度效率超快, API 非常簡潔,線程處理非常棒的持久化解決方案.


后記

? ? ? ? 第一次寫技術文章,誠惶誠恐,其實從代碼角度來說,并沒有分享什么優(yōu)質代碼,而且廢話比較多,可能是因為我個人嘴太碎.這篇文章只是針對自己對于 Realm 的使用做了一些總結,并希望分享出去,這樣如果我有理解的不對或者值得討論的地方,也可以盡快的糾正,當然如果這邊文章可以幫到誰,哪怕只有那么一丟丟,我也就心滿意足了

? ? ? ? 其實關于 Realm 的線程處理還有很多更好的方法,如果有機會和時間我會隨著業(yè)務的深入,再次進行探索,并將心得分享出來共勉.

? ? ? ?如果有問題或者不對地方我會及時更正.

/*************************** ?2016 - 10 - 18 第一次更新 ****************************/

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末至耻,一起剝皮案震驚了整個濱河市锰茉,隨后出現(xiàn)的幾起案子成黄,更是在濱河造成了極大的恐慌,老刑警劉巖志鹃,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肠槽,死亡現(xiàn)場離奇詭異悍缠,居然都是意外死亡雁乡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門街望,熙熙樓的掌柜王于貴愁眉苦臉地迎上來倦沧,“玉大人,你說我怎么就攤上這事它匕≌谷冢” “怎么了?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵豫柬,是天一觀的道長告希。 經常有香客問我,道長烧给,這世上最難降的妖魔是什么燕偶? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮础嫡,結果婚禮上指么,老公的妹妹穿的比我還像新娘。我一直安慰自己榴鼎,他們只是感情好伯诬,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著巫财,像睡著了一般盗似。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上平项,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天赫舒,我揣著相機與錄音,去河邊找鬼闽瓢。 笑死接癌,一個胖子當著我的面吹牛,可吹牛的內容都是我干的扣讼。 我是一名探鬼主播缺猛,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了枯夜?” 一聲冷哼從身側響起弯汰,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤艰山,失蹤者是張志新(化名)和其女友劉穎湖雹,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體曙搬,經...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡摔吏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了纵装。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片征讲。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖橡娄,靈堂內的尸體忽然破棺而出诗箍,到底是詐尸還是另有隱情,我是刑警寧澤挽唉,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布滤祖,位于F島的核電站,受9級特大地震影響瓶籽,放射性物質發(fā)生泄漏匠童。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一塑顺、第九天 我趴在偏房一處隱蔽的房頂上張望汤求。 院中可真熱鬧,春花似錦严拒、人聲如沸扬绪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽勒奇。三九已至,卻和暖如春巧骚,著一層夾襖步出監(jiān)牢的瞬間赊颠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工劈彪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留竣蹦,地道東北人。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓沧奴,卻偏偏與公主長得像痘括,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內容