Realm-cocoa 学习笔记(一)

一、关于Realm

  • Realm 是用于移动端的数据库,目前支持 iOS 和 Android 平台,它相比于 SQLite 和 CoreData 使用简单,学习成本低,性能更高效。

  • Realm 不是基于Core Data,也不是基于SQLite封装构建的。它有自己的数据库存储引擎。

  • Realm 的 iOS 平台开源项目:Realm-cocoa

  • Realm 官方指导文档

  • API查询(objc版)

  • Objective-C 版本的 Realm 的设计目标包含了能够在 Objective-C 和 Swift 混编的项目中使用。

二、安装

  • 在Podfile中,OC工程添加pod 'Realm',Swift工程添加use_frameworks!和pod 'RealmSwift'.(注意需要CocoaPods 0.39.0 或者更高版本)

  • 使用插件管理工具 Alcatraz 安装插件 RealmPlugin 重启Xcode后可以看到:

  • App Store下载一个Realm Browser 的软件,用于查看Realm数据库文件。

三、使用

1.数据模型

  • Realm 数据模型必须直接或间接继承于 RLMObject .

  • Realm 模型对象在形式上基本上与其 他 Objective-C 对象相同,可以给它们添加您自己的方法(method)和协议(protocol).

  • Realm支持以下的属性类型:BOOL、bool、int、NSInteger、long、long long、float、double、NSString、NSDate、NSData 以及 被特殊类型标记的 NSNumber.

  • CGFloat 属性不支持

  • 由于 Realm 在自己的引擎内部有很好的语义解释系统,所以Objective‑C的许多属性特性将被忽略,

  • 如 nonatomic, atomic, strong, copy和weak等。编写数据模型的时候不要使用任何的属性特性。

1.1 Dog 模型的定义


//Dog.h
#import <Realm/Realm.h>
@class Person;

@interface Dog : RLMObject
@property  NSInteger    dogID;
@property  NSString     *name;
@property  NSData       *picture;
@property  NSInteger    age;
@property  NSNumber<RLMFloat> *money;
@property  NSString     *nationality;
@property  NSString     *nothing;
@property  Person       *owner;
@end

//RLM_ARRAY_TYPE 宏创建了一个协议,从而允许 RLMArray<Dog> 语法的使用。
// This protocol enables typed collections. i.e.:
// RLMArray<Dog>
RLM_ARRAY_TYPE(Dog)


//Dog.m
#import "Dog.h"
#import "Person.h"

@implementation Dog

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

/**
 *  重写+defaultPropertyValues可以在每次对象创建之后为其提供默认值。
 */
+ (NSDictionary *)defaultPropertyValues
{
    return @{@"nationality" : @"Chinese"};
}

/**
 *  重写 +ignoredProperties 可以防止 Realm 存储数据模型的某个属性。
 */
+ (NSArray *)ignoredProperties
{
    return @[@"nothing"];
}

/**
 *  设置非空属性
 *  尝试给 name 属性设置为 nil 将会抛出一个异常,但是将 picture 属性设置为 nil 却是允许的
 */
+ (NSArray<NSString *> *)requiredProperties{
    return @[@"name"];
}

/**
 *  重写 +indexedProperties 方法可以为数据模型中需要添加索引的属性建立索引
 *  Realm 支持字符串、整数、布尔值以及 NSDate 属性作为索引
 */
+ (NSArray<NSString *> *)indexedProperties{
    return @[@"age"];
}
@end

1.2 Person 模型的定义


	Person.h
	/*
	 * 使用RLMArray<Object *><Object> 和 RLMObject的子类来建立诸如一对多、一对一之类的关系模型。
	 * RLMArray: 属性类型 类似于 NSMutableArray
	 * <Object *>: 属性的特别化(generic specialization),这可以阻止在编译时使用错误对象类型的数组。
	 * <Object>: 此RLMArray遵守的协议,可以让 Realm 知晓如何在运行时确定数据模型的架构。
	 * RLMArray 的类型是固定的,其中只能存放简单的 RLMObject 子类类型
	 */
	
	#import <Realm/Realm.h>
	#import "Dog.h"
	
	@interface Person : RLMObject
	@property NSString               *name;
	@property RLMArray<Dog *><Dog>   *dogs;
	@end
	
	// This protocol enables typed collections. i.e.:
	// RLMArray<Person>
	RLM_ARRAY_TYPE(Person)

1.3 Dog 和 Person 模型的关系操作


- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    [self test1];
    [self test2];
    [self test3];
}

- (void)test1{
    Dog *mydog = [[Dog alloc] init];
    mydog.name = @"大黄";
    mydog.dogID = 0001; //主键不为空
    mydog.age = 1;
    mydog.picture = nil; // 属性的值可以为空
    mydog.money = nil;
    
    // 检索 Realm 数据库,找到小于 2 岁 的所有狗狗
    RLMResults<Dog *> *puppies = [Dog objectsWhere:@"age < 5"];
    NSLog(@"puppies: %ld",puppies.count);// => 0 因为目前还没有任何狗狗被添加到了 Realm 数据库中
    
    //入库
    RLMRealm *realm = [RLMRealm defaultRealm];
    [realm transactionWithBlock:^{
        [realm addObject:mydog];
    }];
    //检索结果会实时更新
    NSLog(@"puppies: %ld",puppies.count);// => 1
    
    // 可以在任何一个线程中执行检索操作
    dispatch_async(dispatch_queue_create("background", 0), ^{
        //检索
        Dog *theDog = [[Dog objectsWhere:@"age == 1"] firstObject];
        RLMRealm *realm = [RLMRealm defaultRealm];
        //修改属性
        [realm beginWriteTransaction];
        theDog.age = 3;
        [realm commitWriteTransaction];
        NSLog(@"name:%@ age:%ld",theDog.name,theDog.age);// => name:大黄 age:3 检索结果会实时更新
    });
    
    //主键查询
    NSLog(@"dogID=0001:%@",[Dog objectForPrimaryKey:@0001].name);// => dogID=0001:大黄
}

- (void)test2{
    //创建
    Dog *mydog = [[Dog alloc] init];
    mydog.name = @"黑子";
    mydog.dogID = 0002;
    mydog.age = 10;
    mydog.picture = nil;
    mydog.owner = nil;
    
    Person *leoo = [[Person alloc] init];
    leoo.name = @"leoo";
    mydog.owner = leoo;//通过这个属性完成一对一的关系绑定
    
    //入库
    RLMRealm *realm = [RLMRealm defaultRealm];
    [realm transactionWithBlock:^{
        [realm addObject:mydog];
        [realm addObject:leoo];
    }];
    
    //查询
    Dog *heizi = [[Dog objectsWhere:@"name contains '黑子'"] firstObject];
    NSLog(@"%@",heizi.owner.name);// => leoo
}

/**
 * 可以给 RLMArray 属性赋值为 nil,但是这仅用于“清空”数组,而不是用以移除数组。
 * RLMArray 会确保插入 nil 后次序不会被扰乱。
 */
- (void)test3{
    Dog *xiaoBai = [[Dog alloc] init];
    xiaoBai.name = @"xiaoBai";
    xiaoBai.dogID = 0003;
    Dog *xiaoHong = [[Dog alloc] init];
    xiaoHong.name = @"xiaoHong";
    xiaoHong.dogID = 0004;
    
    Person *leoo = [[Person objectsWhere:@"name contains 'leoo'"] firstObject];
    NSLog(@"%@ have %ld dog",leoo.name,leoo.dogs.count); // =>  leoo have 0 dog
    
    RLMRealm *realm = [RLMRealm defaultRealm];
    //修改属性  一对多关系
    [realm beginWriteTransaction];
    
    /* Person 实例的 dogs 属性添加新的 Dog,并不会自动将狗的 owner 属性设置为该 Person。*/
    [leoo.dogs addObjects:@[xiaoHong,xiaoHong]];
    
    [realm commitWriteTransaction];
    
    //检索结果会实时更新
    NSLog(@"%@ have %ld dog",leoo.name,leoo.dogs.count);// =>  leoo have 2 dog
}

1.4 模型类的继承


允许操作

  • 父类中的类方法,实例方法和属性可以被它的子类所继承
  • 子类中可以在方法以及函数中使用父类作为参数

不允许操作

  • 多态类之间的转换(例如子类转换成子类,子类转换成父类,父类转换成子类等)
  • 同时对多个类进行检索
  • 多类容器 (RLMArray 以及 RLMResults)

官方文档示例:类组合模式

	// 基础模型
	@end
	
	@interface Animal : RLMObject
	@property NSInteger age;
	@end
	@implementation Animal
	@end
	
	// 包含有 Animal 的模型
	@interface Duck : RLMObject
	@property Animal *animal;
	@property NSString *name;
	@end
	@implementation Duck
	@end
	
	@interface Frog : RLMObject
	@property Duck   *duck;
	@property NSDate *dateProp;
	@end
	@implementation Frog
	
	// 用法
	Duck *duck =  [[Duck alloc] initWithValue:@{@"animal" : @{@"age" : @(3)}, @"name" : @"Gustav" }];
	   
	Frog *frog = [[Frog alloc] initWithValue:@{@"duck":@{@"animal" : @{@"age" : @(3)}, @"name" : @"Gustav" },@"dateProp":[NSDate date]}];

2.集合

  • RLMResults类,表示从检索 中所返回的对象集合。
  • RLMArray类,表示模型中的对多关系,只能够包含 RLMObject 类型,不能包含诸如NSString之类的基础类型。
  • RLMLinkingObjects类,表示模型中的反向关系。
  • RLMCollection协议,定义了所有 Realm 集合所需要遵守的常用接口。
posted @ 2016-07-07 11:11  moyazi  阅读(1251)  评论(0编辑  收藏  举报