构思了好久,参考了很多人的代码,主要是参考同事的,尝试写了下数据层。
博文地址 http://linit.space/chi-jiu-hua-shu-ju-ceng-da-jian/
==github地址 pod文件还在制作中 https://github.com/Lin-IT-Lion/GQDataBase ==
设计思路
起初是想设计一个通用的构架,底层数据存储的实现方式可以任意替换,鉴于起太复杂,就先设计一个以Realm为数据核心的数据层,当然也可以设计的最终效果是这个核心可以任意替换,替换后上层用到数据存储的部分不需要变动。
一. 构架设计
==适用的模式还是中规中矩的MVC。
上层业务使用的NormalModel可以不做变动,并且可以直接用NormalModel提供的方法进行数据操作。数据存储都由ModelDBContext操作NormalDBModel去实现。==
从图中可以看出,NormalModel与NormalDBModel可以用过一个ModelTransformer类进行互相的转化,数据的流向是将NormalModel转成NormalDBModel后存入数据库,反之亦然。用户使用的话,通过调用原本NormalModel的一些方法就可以实现数据存储。
二. 具体设计
==假设前提:用户使用MVC的方式==
从直接暴露给用户接触的接口说起。首先要使得用户原有的Model可以直接调用增删改查方法。那么就必须给原有的 Model 加上对应的方法,于是便需要提供一个 Category , 给 NSObject 类加上对应的方法定义如下
@interface NSObject (GQDBOperation)
/**
* 增加or修改
*/
- (BOOL)gq_DBaddOrUpdate;
/**
* 删除
*/
- (BOOL)gq_DBdel;
/**
* 查询
*
* @param predicate 正则
*
* @return 结果
*/
+ (NSArray *)gq_DBgetObjectsWithPredicate:(NSPredicate *)predicate;
/**
* 查询全部
*
* @return 结果
*/
+ (NSArray *)gq_DBgetAllObject;
/**
* 删除全部
*
*/
+ (BOOL)gq_DBdelAll;
@end
这样上层用户只需要直接调用对应的方法就可以了。
接下来要进行这些方法的具体实现,在之前的构架设计中已经提到,我们需要进行Model转化然后进行数据存储操作。但是要由原来的Model转化为我们的DBModel。定义DBModel的方式很多,反正我们先定一个BaseDBModel(继承自RLMObject),所有的DBModel都继承与他。(后来我想了下,dbmodel可能也可以不用自己定义,可以使用runtime的特性,动态生成对应类,不过这个暂时放在以后研究,本文还是用最简单的方法,自行定义) 普通的model定义DBModel的形式非常简单,只需要继承自BaseDBModel然后各个字段根据Realm的特性进行定义即可。如:
#import "GQSecNormalModel.h"
@interface GQNormalModel : NSObject
@property (nonatomic, copy) NSString *title;
@property (nonatomic, strong) NSNumber *nId;
@property (nonatomic, strong) GQSecNormalModel *oneModel;
@property (nonatomic, strong) NSMutableArray *oneModelList;
@end
@interface GQSecNormalModel : NSObject
@property (nonatomic, copy) NSString *smallTitle;
@property (nonatomic, copy) NSString *smallTitle1;
@end
@interface GQSecNormalDBModel : GQBaseDBModel
@property (nonatomic, copy) NSString *smallTitle;
@property (nonatomic, copy) NSString *smallTitle1;
@end
RLM_ARRAY_TYPE(GQSecNormalDBModel)
@interface GQNormalDBModel : GQBaseDBModel
@property (nonatomic, strong) NSNumber<RLMInt> *nId;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, strong) GQSecNormalDBModel *oneModel;
@property (nonatomic, strong) RLMArray<GQSecNormalDBModel> *oneModelList;
@end
转换成DBModel之后,通过自定义的ModelDBContext进行数据库操作,当然,也可以直接通过DBModel操作数据库,之所以拆分开来只是为了代码逻辑更加清楚。
三. 具体实现
实现不在本文讨论范围内,直接传代码至github,大家自行参考。
四. 细节问题
- 为了使得框架与项目的耦合程度低一点,获取一些用户的信息,采用协议的方式。通过实现协议方法,返回给数据层一些必要的用户信息。
- 方便DBModel和普通Model的转化,采用Realm+json
- 主要通过协议的方式,提示用户去设置主键,与存储范围(用户相关or无关)
五. 性能分析
主要和Sqlite进行对比,调用Sqlite的方式采用第三方FMDB
从图中可以看出Realm明显在存储的过程中明显快于Sqlite,同样存储10000条数据,Sqlite需要6219ms,Realm仅仅需要1370ms,在读取操作的时候,Realm仅仅需要13ms而Sqlite需要94ms(图中的Realm 使用 1656ms并不是都在读取数据库而是做model转化,读取数据仅耗时13ms,实则存储过程中,真正存储的也只有300ms图中没有截图,其余1000ms也在model转化,而model转化是本框架做的与Realm无关)。
可见,使用Realm远好于Sqlite。