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

結(jié)識(shí) Realm 的催化劑

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

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

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

初識(shí) Realm

? ? ? ? Realm是一個(gè)跨平臺(tái)的移動(dòng)數(shù)據(jù)庫(kù)引擎,而且,它是專門為移動(dòng)端數(shù)據(jù)應(yīng)用設(shè)計(jì)的數(shù)據(jù)持久化方案.不論是 CoreData,還是傳統(tǒng)的SQLite,代碼都些許冗余.CoreData的笨拙的API和FMDB相對(duì)不那么面向?qū)ο蟮牟僮鞣绞?可能會(huì)很多人望而卻步或萌生停用的念頭,那么這個(gè)時(shí)候,Realm 出現(xiàn)了.

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

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

??1.由于 RLMArray 的關(guān)系,這句話一定要寫,來定義 RLMArray 中的實(shí)例,不然會(huì)崩潰

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

3.主鍵

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

4.線程

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

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

蛋疼的開始

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

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

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

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

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

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



#pragma mark 這是第一個(gè)子線程? 這里面進(jìn)行更新寫入

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號(hào)",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 這是第二個(gè)子線程? 這里面是查詢

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

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

[InfomationModel allObjects];

});

#pragma mark 這里是第三個(gè)子線程? 這里是更新寫入加查詢? 回到主線程后繼續(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號(hào)",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號(hào)",i];

model.age = i;

RLMRealm *relam = [RLMRealm defaultRealm];

[relam transactionWithBlock:^{

[relam addOrUpdateObject:model];

[relam commitWriteTransaction];

}];

}

});

});

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

三個(gè)子線程

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

由于MVCC 架構(gòu),不會(huì)阻塞讀寫

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


后記

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

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

? ? ? ?如果有問題或者不對(duì)地方我會(huì)及時(shí)更正.

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,908評(píng)論 6 541
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,324評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,018評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,675評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,417評(píng)論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,783評(píng)論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,779評(píng)論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,960評(píng)論 0 290
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,522評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,267評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,471評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,009評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,698評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,099評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,386評(píng)論 1 294
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,204評(píng)論 3 398
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,436評(píng)論 2 378

推薦閱讀更多精彩內(nèi)容