Realm的常规使用与线程中的坑

结识 Realm 的催化剂

       在我们公司的项目迭代中,由于在之前的聊天这个模块关于用户信息的传值有问题,而之前因为项目经过很多开发者的手,且不提整体的架构有多混乱,就单说缓存这块,就是乱的不行,有的地方用CoreData,有的地方用FMDB, 而且封装的Manager中方法的声明很乱,存取的逻辑也不是很清晰,于是造成了很多我需要取到数据的时候,根本取不到,而当我修改大部分本次版本迭代的需求时,发现这个取不到值问题如果继续沿用之前的逻辑就会非常的麻烦,我要用很多额外方法去跳过之前的坑,只是我决定,在群组聊天的功能中,将用户数据的传值这块逻辑重构.     

        传值的逻辑还是比较好重构的,我将原有用在这里的 CoreData代码全部都清掉,让整体功能即使不依赖于缓存,依旧可以正确及时的取到需要的数据,只是需要等待服务器的响应,但是如果每次都去走服务端的网络请求,那么体验就太差了,那么缓存便是很重要的一步.

        之前说过,现有项目有,有的地方采用了 CoreData,有的用了 FMDB,十分混乱,而我们的用户量还并涉及不到数据迁移的问题.所以我想采用另一套缓存框架来完成我的需求,那么我第一个想到的就是 Realm.

初识 Realm

        Realm是一个跨平台的移动数据库引擎,而且,它是专门为移动端数据应用设计的数据持久化方案.不论是 CoreData,还是传统的SQLite,代码都些许冗余.CoreData的笨拙的API和FMDB相对不那么面向对象的操作方式,可能会很多人望而却步或萌生停用的念头,那么这个时候,Realm 出现了.

      Realm既不是 CoreData,也不是SQLite,它拥有自己的数据库存取引擎,它可以跨平台使用,也意味着更加快速的存取速度,官方给出的Realm的存取速度比 CoreData快了3倍,但是据说在实际使用中,当数据量很大时候,Realm的速度比 CoreData 快了不值30倍.

      说了这么多,你一定对 Realm 也有了些许好感,这篇文章中我并打算介绍关于 Realm 的使用方法,因为文档Relam的官方文档中写的清清楚楚,网上很多大神也做了相关介绍,但是大多数的博客中方法的介绍都是局限在了 Demo 的使用中,真的作用于项目的很少,我在此也算卖弄卖弄我在植入到实际项目时所遇到的小坑或者经验吧.

  1.由于 RLMArray 的关系,这句话一定要写,来定义 RLMArray 中的实例,不然会崩溃

   2.由于数据模型已经由继承与 NSObject 的 Model, 改为了继承于 RLMObject,所以在使用 KVC 的时候一定要注意.

3.主键

如果你想要更新数据,主键是不错的选择

4.线程

       线程问题的坑是我这篇文章所要说的重点.其实 Realm 在关于线程的处理上已经帮我们做了很多事情,我自己并不需要讲过多的精力放在线程上,但是 Realm 本身的线程管理非常严格,所以我们必须遵守Realm 的使用方式,这就使得坑与有点并存

        原本我最开始关于缓存的设计思路是,我从服务端拿到了数据,那么我会把数据放入内存中的数组容器中,再存入数据库中,那么下次进入这个页面我就可以先从数据库中拿到数据后放入容器,再通过服务端进行更新,也是说在当前 Controller 中,我只需要通过数组容器进行赋值就可以了.然而 Realm 并不允许你这样,当我将数据存入 Realm 后,我还没有进行取数据的操作,我只是用数据容器,但这时,程序崩溃了, WTF????!!!! 查看一下崩溃信息 Realm accessed from incorrect thread(从错误的线程访问),当时我就委屈了,我存的时候没有崩溃,也没取啊,怎么就崩溃的,后来我又不得已的用蹩脚的英语水平仔细研读了一下原文文档.

蛋疼的开始

同一个 Realm提交过写入就可以在其他线程被各种蹂躏
Realm的实例不是安全线程的不能在其他线程或列队被访问

卧槽???看的我是万脸懵逼!!

       于是我就交了个 Realm的技术交流群,开始,还有人跟我交流交流使用心德,等把把图贴出来,石沉大海一般,可能是两张截图暴露我的智商和理解能力,大家不想跟差生玩儿...好吧,本着 API 文档就像游戏攻略一样的原则,看不懂的,就带着疑问去玩一玩...那么既然增没事儿,改删查也都没做,那问题会不会出现在了 RLMObject 的调用上,于是在遍历使用之前说的数组容器的地方,打印了当前线程,嗯,果然不是主线程,那既然说同一个 Realm 只要提交了写入就可以在其他线程改变,那我于是试了试 [RLMObject  objectWhere:@"查询条件"],发现就完全没有问题的,那原因到底是什么呢?于是我又开始啃文档

你可以有任意数量的线程并行工作在同一个Realm
只是唯一要注意的是你不能在多个线程共享同一个 RealmObject实例

        这就非常清晰了, Realm 本身在工程中的调用也是个单例类[RLMRealm defaultRealm],所以只要是同一个 Realm, 就可以在任意线程,哪怕是多个线程中,随意使用,不需要锁,只需要将 commitWriteTransaction就可以.但是 RLMObject 的使用的限制就非常严格的,主线程里创建的 RLMObject 就只能在主线程里用,在其他线程中调用的这个它的实例就会抛出异常,有人说,这是 Realm的线程坑,但是我觉得这个是 Realm 对线程做的最好的处理

为此我特意写了一段非常欠打的代码,来验证 Realm 是如何处理并发问题的



#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 这里是第三个子线程  这里是更新写入加查询  回到主线程后继续更新写入加查询

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 各自存取

三个子线程

从时间上来看,形成了一个小规模的并发,也是说,会在Realm可能同时即被读,又被写,但是完全没有报出异常,程序流畅运行,数据也没有出现错误.

由于MVCC 架构,不会阻塞读写

关于 Realm 就先说到这里,其实 Realm 也有很多不便之处,比如我们的模型必须要继承RLMObject,他的RLMArray也并不是 NSArray类型,所以从代码的独立性角度上来说,就不是特别的完美,如果本身项目中有一套完整严格的数据协议,那么 Realm 可能就不会是一个好的选择,而且本身自带 Model,也被很多架构师的去 Model 化思想想违背,但这并不妨碍它是一套专门用于移动端,速度效率超快, API 非常简洁,线程处理非常棒的持久化解决方案.


后记

        第一次写技术文章,诚惶诚恐,其实从代码角度来说,并没有分享什么优质代码,而且废话比较多,可能是因为我个人嘴太碎.这篇文章只是针对自己对于 Realm 的使用做了一些总结,并希望分享出去,这样如果我有理解的不对或者值得讨论的地方,也可以尽快的纠正,当然如果这边文章可以帮到谁,哪怕只有那么一丢丢,我也就心满意足了

        其实关于 Realm 的线程处理还有很多更好的方法,如果有机会和时间我会随着业务的深入,再次进行探索,并将心得分享出来共勉.

       如果有问题或者不对地方我会及时更正.

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,783评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,360评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,942评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,507评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,324评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,299评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,685评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,358评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,652评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,704评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,465评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,318评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,711评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,991评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,265评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,661评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,864评论 2 335

推荐阅读更多精彩内容