最近在搞IM,因为消息量多,实时读写及并发相当的多,原项目封装使用了FMDB,但这个东西对比于并发多线程读写实在不敢恭维,动不动出现锁导致卡顿,体验极期扯蛋。虽然实现队列读写,但是还是管不住这东西的缺陷。。于是乎寻找替换方案。
首先考虑了WCDB,即微信团队发布的开源数据库,但是使用起来相当的别扭,所有属性字段得一个一个的去使用他的宏去声明,工作太繁锁,相信软件及开源的初衷一定是减少开发者的代码耦合及胶水坨坨。
再次考虑都查了Realm这个开源库,库本身为500多M,使用后各种崩溃,100%都是跨线程使用,虽然这个东西,官方说明是线程并发安全的,经过测试也确实是安全的,但是当你使用不当,则全面崩溃异常。原因就是我们的原则数据处理在子线程,刷新UI在主线程。我们在子线程配合加载器(类似于toast)加载数据 ,在主线程使用刷新页面,这个时候,这个东东就不安全了,各种内部线程检查崩溃,对于已有的项目,去适配他的理念及其思想,明显是不明智的,你也不知道哪里要改,哪里要去检查,这样完完全全不是开发的思维,只会白白浪费时间与精力。
故而在寻思realm的安全使用方案,不得不进行解耦,剥离他的内部线程管理方案。即我只用你保存、读取数据 ,页面中的数据model完全是独立于Realm管理的,这个使用方案必定会影响realm的使用性能,但是为了快速在项目中集成使用,不得不这么做。
先来看看这个东西怎么使用:
Realm官网介绍了很多,奈何时间有限,无法去通读,只能从网上查询总结一二,Realm最吸引人的优点就三点:
-
跨平台:现在很多应用都是要兼顾iOS和Android两个平台同时开发。如果两个平台都能使用相同的数据库,那就不用考虑内部数据的架构不同,使用Realm提供的API,可以使数据持久化层在两个平台上无差异化的转换。
-
简单易用:Core Data 和 SQLite 冗余、繁杂的知识和代码足以吓退绝大多数刚入门的开发者,而换用 Realm,则可以极大地减少学习成本,立即学会本地化存储的方法。毫不吹嘘的说,把官方最新文档完整看一遍,就完全可以上手开发了。
-
可视化:Realm 还提供了一个轻量级的数据库查看工具,在Mac Appstore 可以下载“Realm Browser”这个工具,开发者可以查看数据库当中的内容,执行简单的插入和删除数据的操作。毕竟,很多时候,开发者使用数据库的理由是因为要提供一些所谓的“知识库”。
“Realm Browser”这个工具调试起Realm数据库实在太好用了,强烈推荐。
如果使用模拟器进行调试,可以通过
[RLMRealmConfiguration defaultConfiguration].fileURL
打印出Realm 数据库地址,然后在Finder中⌘⇧G跳转到对应路径下,用Realm Browser打开对应的.realm文件就可以看到数据啦.
如果是使用真机调试的话“Xcode->Window->Devices(⌘⇧2)”,然后找到对应的设备与项目,点击Download Container,导出xcappdata文件后,显示包内容,进到AppData->Documents,使用Realm Browser打开.realm文件即可.
安全使用,这里我就直接贴这个兄台的分享经验内容:
大家去看集成使用即可。本文的重点是在解耦,即在我们项目中安全的多线程中使用realm的读写。
贴上以下代码:IMSessionDaoScheme.h文件内容
//
// IMSessionDaoScheme.h
// IMCode
//
// Created by carbonzhao on 2022/6/10.
//
//
#if __has_include(<Realm/Realm.h>)
#import <Realm/Realm.h>
@interface RLMStringModel : RLMObject
@property (copy,nonatomic) NSString *strValue;
@end
RLM_ARRAY_TYPE(RLMStringModel)
/**根据REALM原则 ,数据查询在什么线程则在什么线程使用,跨线程使用查询出来的RLMObject及其他对象,均会崩溃。IMSessionDaoScheme实现解耦,所有查询出来的RLMObject进行二次对象替换,保证数据为非REALM托管的对象。*/
@interface IMSessionDaoScheme : RLMObject
//RLMObject实现已经阉割了OC的RUNTIME方法,无法通过class_copyPropertyList来获取其属性及值
+ (NSArray <NSString *>*)allKeys;
- (NSMutableDictionary *)keysValues;
//增、改
- (void)save2Dao;
+ (void)save2Dao:(NSArray <IMSessionDaoScheme *>*)resArr;
//修改某个属性值
- (void)updateOncePropertyValue:(void (^)(id thisModel))ablock;
//删
- (void)deleteFromDao;
+ (void)deleteFromDao:(NSArray <IMSessionDaoScheme *>*)resArr;
+ (void)deleteAll;
+ (NSMutableArray <IMSessionDaoScheme *>*)queryAll;
+ (NSMutableArray <IMSessionDaoScheme *>*)queryFromDaoWithStatement:(NSDictionary *)stej;
+ (NSMutableArray <IMSessionDaoScheme *>*)queryFromDaoWithWhere:(NSString *)sttext;
/**查 ifAnd=yes,sql statement will be liked key=1 AND key1=2,other else key=1 OR key1=2....,
sortedKey can be key desc,key1 asc,use ',' seperator the statement
*/
+ (NSMutableArray <IMSessionDaoScheme *>*)queryFromDaoWithStatement:(NSDictionary *)stej ifAnd:(BOOL)ifAnd sortedKey:(NSString *)sortedKey;
@end
// This protocol enables typed collections. i.e.:
// RLMArray<IMSessionDaoScheme *><IMSessionDaoScheme>
RLM_ARRAY_TYPE(IMSessionDaoScheme)
#endif
IMSessionDaoScheme.m文件内容
//
// IMSessionDaoScheme.m
// IMCode
//
// Created by carbonzhao on 2022/6/10.
//
//
#import "IMSessionDaoScheme.h"
#import "JsonKit.h"
#import "NSExtentionSloter.h"
#import "IMDataConfigTools.h"
#if __has_include(<Realm/Realm.h>)
@implementation RLMStringModel
@end
@interface IMSessionDaoScheme ()
@property (nonatomic,strong) NSString *usersTable;
@property BOOL spcyInMainThread;
@end
@implementation IMSessionDaoScheme
#pragma mark - daoLayer
+ (NSArray *)ignoredProperties
{
return @[@"spcyInMainThread"];
}
+ (NSArray *)allKeys
{
Class csName = [self class];
IMSessionDaoScheme *aj = [[csName a