薄荷冷冰冰

iOS移动端数据库Realm尝试

#前言:

数据处理是app中不可避免的问题,少量的数据可以考虑使用归档存在本地,但是如果大量的数据根本不能这样使用,之前的解决方案是使用SQLite,传统的数据库,或者是apple自家的Core Data.但是sqlite是使用c语句,而且步骤繁杂,几乎我每次使用数据库都会去google sql语句.同样Core Data也是十分麻烦. 所以需要找到另一个解决数据存储的问题.久闻realm大名,优点简单易懂,还有GUI,正好符合我的心意,所以.今天就来试试realm.

首先

贴出realm官网,刚刚开始看到的时候,哇,还有中文,太好了,然而进去发现,有些节目有中午,有些则没有,而且中文文档不是最新的.要什么自行车
官网其实有点乱,一般习惯使用cocoapods,但是不知道为什么安装的时候特别慢,但是在官网找了好久都没有找到下载framework的地方.
原来存放文档的网页,下面就是下载链接..

  1. 注意 注意.静态库 值得注意的是,需要Xcode8.
  2. realm2.4.3下载链接
  3. cocoapods的话 则输入 pod Realm

初次接触

按照官方的文档,使用是非常的简单的.导入#import <Realm/Realm.h>
添加一个子类,继承RLMObject.添加2个熟悉

@interface dog : RLMObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;
@end

然后初始化,复制,添加到数据库一气呵成.再查找,打印

dog *newDog = [[dog alloc]init];
newDog.age = 222;
newDog.name = @"旺财";
RLMRealm *realm = [RLMRealm defaultRealm];
[realm transactionWithBlock:^{
    [realm addObject:newDog];
}];
RLMResults *results = [dog objectsWhere:@"age > 212"];
NSLog(@"%lu",(unsigned long)results.count);

然后就能成功了

真的有这么一帆风顺么?

并没有,之前按照文档进行这个入门的测试,下意识的把age定义成了String类型,然后查询的时候并不能查询出来,然后就把age的类型改为NSInteger.然后程序就开始疯狂崩溃
错误代码:

2017-03-07 18:46:05.673296 realm[4857:3090351] *** Terminating app due to uncaught exception 'RLMException', reason: 'Migration is required due to the following errors:
- Property 'dog.age' has been changed from 'int' to 'string'.

百度了一下,发现如果你修改了属性的类型,那么你需要卸载APP,重新安装.讲道理,这个有点麻烦.

然后Realm还准备了Realm Browser,提供GUI去查看数据库.

查看数据库

首先,找到你app对应的Realm的文件

Window-Device-选择你安装的手机-选择app-点击设置按钮-download container


这样,你就能获得一个.xcappdata文件,显示包内容-AppData-Documents-default.realm,双击就可以打开了

然而我的Realm Browser无限崩溃.只好继续代码学习
在另外2台电脑上都可以打开,估计公司的Mac是假的.

数据模型(Model)

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

官网表示有很多类型,但是这个特殊类型标记的属性类型不知道什么意思,估计下面会讲.

RLMObject 能够借助 RLMObject 以及 RLMArray属性来和另一个 RLMObject 建立联系。 RLMArray 的接口和 NSArray 非常类似,在 RLMArray 中的对象能够通过索引下标(indexed subscripting)进行访问。 与 NSArray 所不同的是,RLMArray 的类型是固定的,其中只能存放简单的 RLMObject 子类类型。

之前实现了RLMObject,试试以下数组类型的.

@property (nonatomic, copy) RLMArray<dog *> *dog;
[perSon.dog addObject:newDog];

正常地NSArray的方法是可以用的,但是@[]不适用.

虽然可以给 RLMArray 属性赋值为 nil,但是这仅用于“清空”数组,而不是用以移除数组。这意味着您总是可以向一个 RLMArray 属性中添加对象,即使其被置为了 nil。

这条也显示跟NSArray的差别

属性特性(attributes)

注意由于 Realm 在自己的引擎内部有很好的语义解释系统,所以 Objective‑C 的许多属性特性将被忽略,如nonatomic, atomic, strong, copy 和 weak 等。 因此为了避免误解,我们推荐您在编写数据模型的时候不要使用任何的属性特性。 当然,如果您已经设置了这些属性特性,那么在 RLMObject 对象被写入 Realm 数据库前,这些特性会一直生效。

这就是为什么我看文档的时候所有的属性没有描述

索引属性(Indexed Properties)

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

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

@implementation Book
+ (NSArray *)indexedProperties {
  return @[@"title"];
}
@end

Realm 支持字符串、整数、布尔值以及 NSDate 属性作为索引。

对属性进行索引可以减少插入操作的性能耗费,加快比较检索的速度(比如说 = 以及 IN 操作符)。

没看懂是什么意思 - -

属性默认值

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

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

@implementation Book
+ (NSDictionary *)defaultPropertyValues {
    return @{@"price" : @0, @"title": @""};
}
@end
对象的自更新特性

RLMObject 实例是底层数据的动态表现,其会进行自动更新,这意味着对象不需要进行刷新。修改某个对象的属性会立刻影响到其他所有指向同一个对象的实例。

Dog *myDog = [[Dog alloc] init];
myDog.name = @"小白";
myDog.age = 1;

[realm transactionWithBlock:^{
  [realm addObject:myDog];
}];

Dog *myPuppy = [[Dog objectsWhere:@"age == 1"] firstObject];
[realm transactionWithBlock:^{
  myPuppy.age = 2;
}];

myDog.age; // => 2

RLMObject 的这个特性不仅让 Realm 保证速度和效率,它同时还让代码更加简洁、更为灵活。比如说,如果您的 UI 代码是基于某个特定> 的 Realm 对象来现实的,那么在触发 UI 重绘之前,您不用担心数据的刷新或者重新检索等问题。

您也可以查看 Realm 通知 一节以确认 Realm 数据何时被更新,比如说由此来决定应用 UI 何时需要被更新。此外,还可以使用 键值编码,当某个 RLMObject 的特定属性发生更新时去发送通知。

这个感觉就很厉害了!

收工,明天继续.