Realm数据库详解
Realm,为移动设备而生。替代 SQLite 和 Core Data。
官方中文文档:官方文档
以上是官方文档,大家看过后有个大体了解。
说一下我对Realm的认识。
首先它的API调用特别舒服,不繁琐。
还有一个好处就是省心,不用像CoreData那样复杂的管理。也不用写SQL语句。总之,简单!
高效,开发中应用测试时,无论是那种操作,都是秒操作。所以性能不是问题。
下面是具体操作(看过官方文档,有一定认识后在操作)
我只是复述一下我对官方文档的理解,以及我集成Realm的过程操作
从这里开始(集成过程)
Realm是开源的~,下载方式静态库,以及官方Demo。下载 Realm OC版(Swift版和OC版是不能共存的):下载OC版Realm
准备工作
使用 Realm 构建应用的基本要求:iOS >= 7, OS X >= 10.9 并且支持 WatchKit。;
需要使用 Xcode 6.4 或者以后的版本;
程序支持Objective‑C, Swift 1.2 & Swift 2.x。
安装 (这里有好多可选的方式,看大家喜欢,我用的是静态库)
1.动态框架
2.CocoaPod
3.Carthage
4.静态框架(因为其他的需要些脚本)
Realm浏览器/数据库管理器
官方提供了一个名为Realm Browser的Mac应用,用来进行Realm数据的读取和编辑。(好用,但是每次编译写入新数据的时候,之前打开的会闪退)
Xcode 插件
怎么安装就不赘述了,最开始的时候我会用,后来用多了,就自己手动建模型类了。
API手册
能查询Realm的完整版API手册,里面包含了所有类和方法等信息。
示例
官方Demo里有(好多,而且是英文不是很懂)
数据模型(Model)
Realm数据模型是基于标准 Objective‑C 类来进行定义的,使用属性来完成模型的具体定义。
通过简单的继承RLMObject或者一个已经存在的模型类,您就可以创建一个新的 Realm 数据模型对象。
Realm模型对象在形式上基本上与其他 Objective‑C 对象相同 - 您可以给它们添加您自己的方法(method)和协议(protocol),和在其他对象中使用类似。
主要的限制是某个对象只能在其被创建的那个线程中使用, 并且您无法访问任何存储属性的实例变量(ivar)。
如果您安装了我们的Xcode插件,那么可在”New File…“对话框中会有一个很漂亮的模板,可用来创建接口(interface)和执行(implementation)文件。
您只需要为对象的类型列表添加目标类型的属性,或者RLMArray,就可以创建数据关系(relationship)和嵌套数据结构(nested data structure)。
我就不用官方文档里的类说明了,以下就是实际项目(gitDemo)中类的创建以及使用
导入项目中的DataStore文件夹
拖进来之后(确保拖入时勾选了 Copy items if needed ),可能会报错,查看报错信息,(一般是缺少libc++.tbd)
建模型的基类
我将常用的数据库操作已经做了封装,在Store文件夹下是Realm数据库的管理类,同时每个模型类都需要主键,所以应该抽象出父类来持有primaryKey和realmManager是有必要的。
模型类需要跟官方文档里描述一致需要继承RLMObject类RLM_ARRAY_TYPE(BasicRealm)定义一个RLMArray类型(不太明白的可以看一下官方源码)
#import <Realm/Realm.h>
#import"RLMObject+JSON.h"
#import"XMRealmStoreManager.h"
@interfaceBasicRealm :RLMObject
/**
*本地数据库入库的主键ID
*/
@property(nonatomic,copy)NSString*hostID;
/**
* realm数据管理
*
* @return realm数据管理
*/
+(XMRealmStoreManager*)realmManager;
-(XMRealmStoreManager*)realmManager;
@end
// This protocol enables typed collections. i.e.:
// RLMArray
RLM_ARRAY_TYPE(BasicRealm)
@interfaceBasicModel :NSObject
@property(nonatomic,copy)NSString*hostID;
@end
.m文件的具体方法请从项目中查看
建数据模型类
现在就可以根据项目需求建立明确的模型类,模型类需要继承上述的基类BasicRealm。
假如现在的需求是Cell的标题下有三张图片(大家自行脑补一下UI),那么我们需要标题属性,以及一个图片链接数组(Realm中不能用NSArray,需要用RLMArray)属性声明如下
#import"BasicModel.h"
RLM_ARRAY_TYPE(ImageRealm)//定义一个RLMArray类型
@interfaceDataRealm :BasicRealm
@property(nonatomic,copy)NSString*title;
@property(nonatomic,strong)RLMArray * image_url;
@end
@interfaceImageRealm :BasicRealm
@property(nonatomic,copy)NSString*image;
@end
.m中需要重写两个方法
+ (NSDictionary*)JSONInboundMappingDictionary
(入库的keyPath对应模型的keyPath)
+ (NSDictionary*)JSONOutboundMappingDictionary
(出库的keyPath对应模型的keyPath)
两个方法一般内容都相同,一般我们写的模型类都是基于服务器返回数据的KeyPath作为我们数据类的属性名。但当服务器返回的数据(比如服务器数据库的主键是id,当然你也可以跟服务端开发商量一下提前做一下key的更改,毕竟好兄弟~)有一些OC的关键词比如id这样的话我们就需要将入(出)库的keyPath对应模型的keyPath做一下映射的更改
@implementationDataRealm
+ (NSDictionary*)JSONInboundMappingDictionary {
return@{
@"hostID":@"hostID",
@"image_url":@"image_url",
@"title":@"title",
};
}
+ (NSDictionary*)JSONOutboundMappingDictionary {
return@{
@"hostID":@"hostID",
@"image_url":@"image_url",
@"title":@"title",
};
}
@end
@implementationImageRealm
+ (NSDictionary*)JSONInboundMappingDictionary {
return@{
@"hostID":@"hostID",
@"image":@"image",
};
}
+ (NSDictionary*)JSONOutboundMappingDictionary {
return@{
@"hostID":@"hostID",
@"image":@"image",
};
}
@end
Realm数据模型类的使用
用Realm管理类调用数据的增删改差
//增or改
-(void)add
{
[[DataRealmrealmManager]writeObjectsWithObjectsBlock:^id(XMRealmOperation*operation,RLMRealm*realm) {
//在这返回一个id对象可以是一个包含多个数据库模型的数组,也可以是单个数据库模型对象可以调用Real自己的解析字典方法,也可以用封装好的方法(根据服务器返回的数据类型)
return[DataRealmcreateOrUpdateInRealm:realmwithJSONDictionary:@{@"hostID":@"1",@"title":@"好好学习天天向上",@"image_url":@[@{@"hostID":@"1",@"image":@"http://image1"},@{@"hostID":@"2",@"image":@"http://image2"},@{@"hostID":@"3",@"image":@"http://image3"}]}];
// return [DataRealm createOrUpdateInRealm:realm withJSONArray:@[]];
}completion:^(XMRealmStoreManager*store,XMRealmOperation*operation,RLMRealm*realm) {
//事务完成后回调
}];
}
//删
-(void)delete{
[[DataRealmrealmManager]deleteObjectsWithObjectsBlock:^id(XMRealmOperation*operation,RLMRealm*realm) {
//可以根据sql语句查找删除
return[DataRealmobjectsWhere:@""];
//也可以根据主键获得
return[DataRealmobjectForPrimaryKey:@"1"];
}completion:^(XMRealmStoreManager*store,XMRealmOperation*operation,RLMRealm*realm) {
//事务完成回调
}];
}
//查
-(void)search
{
[[DataRealmrealmManager]fetchObjectsWithObjectsBlock:^id(XMRealmOperation*operation,RLMRealm*realm) {
//可以根据sql语句查找删除
return[DataRealmobjectsWhere:@""];
//也可以根据主键获得
return[DataRealmobjectForPrimaryKey:@"1"];
}completion:^(XMRealmStoreManager*store,XMRealmOperation*operation,RLMRealm*realm,RLMResults*results,NSString*primaryKey,NSMutableArray*models) {
//事务完成回调获得查询内容更新UI
}];
}
后语:
我建议大家将数据分为两种类,一种是数据库类,一种是平常我们不做数据存储的类(我在Demo (由于git文件大小限制不能上传Realm.framework,请大家自行拖入)中是这样操作的)。这样做的好处是分开来易于管理,那些属性内容需要入库就在数据库类中声明,不需要的但是我们UI展示上需要的在单独的数据类中。这样数据库中就不需要冗余的key(当然也可以通过.m的两种方法来控制入库的keyPath)这样做还有一个不算原因的原因,这样做可以用一些字典转模型的解析类框架(比如MJ,YYModel等)。总是这项看个人喜好吧。