Realm笔记

Realm是专门为移动端开发的数据库引擎。它具有跨平台,简单易用,速度快,占用空间小,支持java,objec-c,swift语言等特点,迅速的得到了开发者的青睐。项目中使用了Realm,将中间的过程记录下来以备查阅。

环境

  • 系统:OS X 10.11.5,
  • Xcode:Version 7.2 (7C68)
  • 开发语言:Objective-C

准备

  • 1.下载Realm对应的Objective-C版本。下载地址在这里,选择realm-cocoa下载源代码。

  • 2.将Realm集成到项目。
    Realm框架支持常用的静态库,动态库,CocoaPads和Carthage 几种集成方式。
    本文使用动态库的方式。

  • 首先将下载 Realm 的最新版本并解压;解压后文件如下


    Realm笔记_第1张图片
  • 前往Xcode 工程的”General”设置项中,从ios/dynamic/中将’Realm.framework’拖曳到”Embedded Binaries”选项中。确认Copy items if needed被选中后,点击Finish按钮;

  • 在项目的”Build Phases”中,创建一个新的”Run Script Phase”,并将
    bash "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/Realm.framework/strip-frameworks.sh"
    这条脚本复制到文本框中。

    Realm笔记_第2张图片

  • 下载Realm Browser的Mac应用以便 对.realm数据库进行读取和编辑。


    Realm笔记_第3张图片

    同时Xcode也有个Realm Browser的插件。使用Alcatraz安装即可。由于我使用的Xcode7.2版本。会不支持该插件出现想这样的错误。

PluginLoading: Required plug-in compatibility UUID F41BD31E-2683-44B8-AE7F-5F09E919790E for plug-in at path '~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/RealmBrowser.xcplugin' not present in DVTPlugInCompatibilityUUIDs```
解决办法:找到该插件的配置文件,将7.2的UUID添加到配置文件即可。

+ 安装Xcode 插件
RealmPlugin插件可以快速的创建基于RLMObject的模型对象。
![](http://upload-images.jianshu.io/upload_images/1101711-6a8c11404f0cb0f0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
安装完成后,直接command + N新建对应的模型文件。
![](http://upload-images.jianshu.io/upload_images/1101711-a5af9f65646bfa79.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


####Realm数据模型
Realm数据模型是基于标准 Objective-C 类来进行定义的,使用属性来完成模型的具体定义。
通过简单的继承 RLMObject 或者一个已经存在的模型类,您就可以创建一个新的 Realm 数据模型对象。

构建一个银行卡模型BankInfo

import

import

@interface BankInfo : RLMObject
//银行卡信息
@property (nonatomic, copy) NSString *bank_accnoalias;
@property (nonatomic, copy) NSString *bank_accname;
@property (nonatomic, copy) NSString *bankname;
@property (nonatomic, copy) NSString *bankid;
@property (nonatomic, copy) NSString *status;
@property (nonatomic, copy) NSString *acc_nature;
@property (nonatomic, copy) NSString *bank_accno;

+(instancetype)bankInfoWithDict:(NSDictionary * )dict;
-(instancetype)initWithBankDict:(NSDictionary *)dict;

@end

RLM_ARRAY_TYPE(BankInfo)


构建持卡人模型Person

import

import "BankInfo.h"

@interface Person : RLMObject
@property NSString *name;
@property RLMArray *banks;
@end


+ 其中在BankInfo模型类的声明的结尾使用RLM_ARRAY_TYPE(BankInfo)宏来创建一个协议,从而允许 RLMArray 语法的使用。
然后在Person模型类中声明属性```@property RLMArray *banks;```这样两个类构建成了一对多的关系。
  > 如果是互相包含的关系呢?
  在Realm中通过反向关系来实现即:
  ```@property (readonly) RLMLinkingObjects *owners;```
  先在BankInfo模型类声明声明owners属性,然后重写 +[RLMObject linkingObjectsProperties] 来指明关系,说明 ownders 中包含了 Person 模型对象。

具体代码

@interface BankInfo : RLMObject
@property (readonly) RLMLinkingObjects *owners;
@end
RLM_ARRAY_TYPE(BankInfo)

@implementation BankInfo

  • (NSDictionary *)linkingObjectsProperties
    {
    return @{ @"owners": [RLMPropertyDescriptor descriptorWithClass:Person.class propertyName:@"banks"] };
    }
    @end

@interface Person : RLMObject
@property NSString *name;
@property RLMArray< BankInfo > *banks;
@end

@implementation Person
@end


+ Realm支持以下的属性类型:BOOL、bool、int、NSInteger、long、long long、float、double、NSString、NSDate、NSData 以及 被特殊类型标记的 NSNumber 。CGFloat 属性的支持被取消了,因为它的类型不依赖于平台。

+ 模型类属性是否可以为nil

@interface Person : RLMObject
@property NSString *name;
@property NSDate *birthday;
@end

@implementation Person

  • (NSArray *)requiredProperties {
    return @[@"name"];
    }
    @end
重写了requiredProperties方法代表name不能为nil

+ 添加索引
重写 +indexedProperties 方法可以为数据模型中需要添加索引的属性建立索引

@interface Book : RLMObject
@property float price;
@property NSString *title;
@end

@implementation Book

  • (NSArray *)indexedProperties {
    return @[@"title"];
    }
    @end
Realm 支持字符串、整数、布尔值以及 NSDate 属性作为索引。

+ 添加属性默认值
重写+defaultPropertyValues可以在每次对象创建之后为其提供默认值。

@interface Book : RLMObject
@property float price;
@property NSString *title;
@end

@implementation Book

  • (NSDictionary *)defaultPropertyValues {
    return @{@"price" : @0, @"title": @""};
    }
    @end

+ 设置主键
重写 +primaryKey 可以设置模型的主键。声明主键之后,对象将被允许查询,更新速度更加高效,并且要求每个对象保持唯一性。 一旦带有主键的对象被添加到 Realm 之后,该对象的主键将不可修改。

@interface Person : RLMObject
@property NSInteger id;
@property NSString *name;
@end

@implementation Person

  • (NSString *)primaryKey {
    return @"id";
    }
    @end

+ 忽略属性
重写 +ignoredProperties 可以防止 Realm 存储数据模型的某个属性

@interface Person : RLMObject
@property NSInteger tmpID;
@property (readonly) NSString *name; // 只读属性将被自动忽略
@property NSString *firstName;
@property NSString *lastName;
@end

@implementation Person

  • (NSArray *)ignoredProperties {
    return @[@"tmpID"];
    }
  • (NSString *)name {
    return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];
    }
    @end

####Realm集合
Realm 拥有一系列能够帮助表示一组对象的类型,我们称之为『Realm 集合』:
RLMResults类,表示从检索 中所返回的对象集合。
RLMArray类,表示模型中的对多关系。
RLMLinkingObjects类,表示模型中的反向关系。
RLMCollection协议,定义了所有 Realm 集合所需要遵守的常用接口。

####Realm增删改查
将常用的增删改查进行封装,代码如下。

// 构建Realm数据库
RLMRealm *realm = [RLMRealm defaultRealm];
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
[RLMRealmConfiguration setDefaultConfiguration:config];

// Realm内存数据库
//RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
//config.inMemoryIdentifier = @"MyInMemoryRealm";
//RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:nil];
//self.rlmRealm = realm;// 在使用Realm内存数据库的时候,必须使用强指针引用,如果某个内存 Realm 数据库实例没有被引用,那么所有的数据就会被释放。

// 增加数据

  • (BOOL)realmsInsertData:(NSArray *)data{

    NSError *error;

    // Add an object
    [self.rlmRealm beginWriteTransaction];
    for (int i = 0; i < data.count; i++) {

      BankInfo *obj = [[BankInfo alloc] initWithBankDict:data[i]];
      [self.rlmRealm addOrUpdateObject:obj];
    

    }
    return [self.rlmRealm commitWriteTransaction:&error];
    }

// 查询数据

  • (id)realmSelectData:(NSString *)object theCondition:(NSString *)condition{

    Class cls = NSClassFromString(object);
    RLMResults *result = [cls objectsInRealm:self.rlmRealm where:condition];
    return result;
    }

// 删除数据

  • (BOOL)realmsDeleteData:(NSString *)object theCondition:(NSString *)condition type:(realmDelType)type{

    Class cls = NSClassFromString(object);
    if (cls == nil) {
    return NO;
    }
    RLMResults *results = [self realmsselectData:[BankInfo className] theCondition:condition];
    if (!results.count) {
    return YES;
    }
    NSError *error = nil;
    // 开始事务
    [self.rlmRealm beginWriteTransaction];
    switch (type) {
    case realmDelTypeAll:
    [self.rlmRealm deleteObjects:[cls allObjectsInRealm:self.rlmRealm]];
    break;
    case realmDelTypeFirst:
    [self.rlmRealm deleteObject:[cls allObjectsInRealm:self.rlmRealm].firstObject];
    break;
    case realmDelTypeLast:
    [self.rlmRealm deleteObject:[cls allObjectsInRealm:self.rlmRealm].lastObject];
    break;
    case realmDelTypeOther:
    [self.rlmRealm deleteObjects:results];
    break;
    default:
    break;
    }
    // 提交事务
    return [self.rlmRealm commitWriteTransaction:&error];

}

// 更新数据

  • (BOOL)realmsUpdateData:(NSString *)object theCondition:(NSString *)condition property:(NSDictionary *)dict{

    Class cls = NSClassFromString(object);
    if (cls == nil) {
    return NO;
    }

    RLMResults *results = [self realmsselectData:object theCondition:condition];
    if (!results.count) {
    return YES;
    }

    if (dict == nil) {
    return NO;
    }

    // 检查属性
    if (![self CheckPropertys:object propertyDict:dict]) {
    return NO;
    }

    NSError *error = nil;
    [self.rlmRealm beginWriteTransaction];

    //将每条数据的每个 属性设置为对应的值
    for (NSString *updateKey in dict.allKeys) {
    [results setValue:dict[updateKey] forKeyPath:updateKey];
    }
    // 如果没有值,就新插入一条数据
    //[cls createOrUpdateInRealm:self.rlmRealm withValue:dict];

    return [self.rlmRealm commitWriteTransaction:&error];
    }

// 检查该类中是否有该属性

  • (BOOL)CheckPropertys:(NSString *)object propertyDict:(NSDictionary *)dict{

    Class cls = NSClassFromString(object);
    // 属性字符串数组
    NSMutableArray *clspropertys = [NSMutableArray array];

    unsigned pCount;
    objc_property_t *properties = class_copyPropertyList(cls, &pCount);//属性数组

    for(int i = 0; i < pCount; i++){
    objc_property_t property = properties[i];
    NSString *str =[NSString stringWithFormat:@"%s", property_getName(property)];
    [clspropertys addObject:str];
    //NSLog(@"propertyName:%s",property_getName(property));
    //NSLog(@"propertyAttributes:%s",property_getAttributes(property));
    }

    NSArray *keys = dict.allKeys;
    for (NSString *dictkey in keys) {
    if ([clspropertys containsObject:dictkey]) {
    NSLog(@"This class does contain attributes.:%@",dictkey);
    }else {
    NSLog(@"This class does not contain attributes.:%@",dictkey);
    return NO;
    }
    }
    return YES;
    }


代码调用

RLMResults *results = [BankInfo objectsInRealm:self.rlmRealm where:@"bank_accno = '6228481234567891235' "];
NSLog(@"results = %@", results);

NSLog(@"banklistselect = %@", [BankInfo allObjectsInRealm:self.rlmRealm]);

//[self realmsDeleteData:NSStringFromClass([BankInfo class]) theCondition:@"bank_accno = '6228481234567891235' or bank_accno = '6228481234567891242' " type:realmDelTypeOther];
//NSLog(@"banklistDelete = %@", [BankInfo allObjectsInRealm:self.rlmRealm]);

[self realmsUpdateData:NSStringFromClass([BankInfo class]) theCondition:nil property:@{@"status":@"6", @"bank_accnoalias":@"123"}];
NSLog(@"banklistUpdate = %@", [BankInfo allObjectsInRealm:self.rlmRealm]);

[self.rlmRealm beginWriteTransaction];
// 先删除数据
[self.rlmRealm deleteObjects:[Person allObjects]];
Person *p = [[Person alloc] init];
p.name = @"张三";
[p.banks addObjects:[BankInfo allObjectsInRealm:self.rlmRealm]];
[self.rlmRealm addObject:p];
[self.rlmRealm commitWriteTransaction:nil];


+ Realm中所有有关数据库的操作都是一个事务。
即所有的代码都需要去被包含在beginWriteTransaction和commitWriteTransaction之间。
+ Realm查询结果,Realm将会返回包含 RLMObject 集合的RLMResults实例。RLMResults 的表现和 NSArray 十分相似,并且包含在 RLMResults 中的对象能够通过索引下标进行访问。和 NSArray 不同,RLMResults 需要指定类型,并且其当中只能包含RLMObject 子类类型的属性。
所有的查询(包括查询和属性访问)在 Realm 中都是延迟加载的,只有当属性被访问时,才能够读取相应的数据。
+ Realm 支持许多常见的断言:
比较操作数(comparison operand)可以是属性名称或者某个常量,但至少有一个操作数必须是属性名称;
比较操作符 ==、<=、<、>=、>、!=, 以及 BETWEEN 支持 int, long, long long, float, double, 以及 NSDate 属性类型的比较,比如说 age == 45;
相等比较 ==以及!=,比如说[Employee objectsWhere:@"company == %@", company]
比较操作符 == and != 支持布尔属性;
对于 NSString 和 NSData 属性来说,我们支持 ==、!=、BEGINSWITH、CONTAINS 以及 ENDSWITH 操作符,比如说 name CONTAINS ‘Ja’;
字符串支持忽略大小写的比较方式,比如说 name CONTAINS[c] ‘Ja’ ,注意到其中字符的大小写将被忽略;
Realm 支持以下复合操作符:“AND”、“OR” 以及 “NOT”。比如说 name BEGINSWITH ‘J’ AND age >= 32;
包含操作符 IN,比如说 name IN {‘Lisa’, ‘Spike’, ‘Hachi’};
==、!=支持与 nil 比较,比如说 [Company objectsWhere:@"ceo == nil"]。注意到这只适用于有关系的对象,这里 ceo 是 Company 模型的一个属性。
通过 ==, != 进行空值比较,比如说 [Company objectsWhere:@"ceo == nil"]; 注意,Realm 将 nil 视为一个特殊的值而不是“缺失值”,不像 SQL 那样 nil 等于自身。
ANY 比较,比如说 ANY student.age < 21
RLMArray 以及 RLMResults 属性支持集合表达式:@count、@min、@max、@sum 以及 @avg,例如 [Company objectsWhere:@"employees.@count > 5"] 用以寻找所有超过 5 名雇员的公司。
支持子查询,不过有限制:
@count 是唯一能应用在 SUBQUERY 表达式中的操作符
SUBQUERY(…).@count 表达式必须与常量进行比较

####其他
在测试的过程中,如果模型类的属性进行了添加或者删除操作,重新执行会报错,重新删除app的数据即可。

最后执行结果
![](http://upload-images.jianshu.io/upload_images/1101711-b0aee6127ac7a8d7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](http://upload-images.jianshu.io/upload_images/1101711-09c7102c120a9b79.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

####参考地址
[官网地址](https://realm.io)
[参考地址1](http://www.cocoachina.com/ios/20150505/11756.html)

你可能感兴趣的:(Realm笔记)