iOS开发-Realm数据库

Realm

Realm-Object-c,见:
https://realm.io/cn/docs/objc/latest/
Realm官网:
https://realm.io

使用流程

  • 导入头文件#import < Realm/Realm.h >.
  • 创建类,继承于RLMObject.
  • 在类中生成数据模型.
  • 在需要的地方创建实例,使用Realm方法调用.

数据模型

创建简单数据模型

简单地,继承RLMObject创建类,在.h中通过属性定义不同的内容.

RLMResults <0x7fe5e3d22ec0>(
    [0]Data {
        time = 2016-01-08 05:51:12 +0000;
        title = test;
    }
)

生成如上的数据结构,只需创建类如下:

// .h
#import <Realm/Realm.h>

@interface Data : RLMObject
@property (nonatomic , strong) NSDate *time;
@property (nonatomic , copy) NSString *title;

@end

// .m
#import "Data.h"

@implementation Data

@end

生成主键(Primary Keys)

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

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

@implementation Person
+ (NSString *)primaryKey {
    return @"id";
}
@end

忽略属性(Ignored Properties)

重写 +ignoredProperties 可以防止 Realm 存储数据模型的某个属性。Realm 将不会干涉这些属性的常规操作,它们将由成员变量(ivar)提供支持,并且您能够轻易重写它们的 setter 和 getter。

@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

属性默认值

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

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

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

创建嵌套数据模型

数据结构:Person具有name、birthdate、dogs,Dog具有name、owner< Person >。

RLMResults <0x7fb431f2bd60> (
    [0] Person {
        name = crylown;
        birthdate = 2016-01-08 06:02:23 +0000;
        dogs = RLMArray <0x7fb431f2fcd0> (
            [0] Dog {
                name = myDog;
                owner = Person {
                    name = crylown;
                    birthdate = 2016-01-08 06:02:23 +0000;
                    dogs = <Maximum depth exceeded>;
                };
            },
            [1] Dog {
                name = yourDog;
                owner = Person {
                    name = crylown;
                    birthdate = 2016-01-08 06:02:23 +0000;
                    dogs = <Maximum depth exceeded>;
                };
            }
        );
    }
)

生成如上的数据结构,创建数据模型代码如下:

// .h
#import <Realm/Realm.h>

@class Person;

// 狗狗的数据模型
@interface Dog : RLMObject
@property NSString *name;
@property Person   *owner;
@end
RLM_ARRAY_TYPE(Dog) // 定义RLMArray<Dog>

// 狗狗主人的数据模型
@interface Person : RLMObject
@property NSString      *name;
@property NSDate        *birthdate;

// 通过RLMArray建立关系
@property RLMArray<Dog> *dogs;

@end
RLM_ARRAY_TYPE(Person) // 定义RLMArray<Person>

// .m
@implementation Dog
@end  // 暂无使用

@implementation Person
@end  // 暂无使用

使用Realm数据模型

创建对象

一般属性

Data *data = [[Data alloc] init];

data.time = [NSDate dateWithTimeIntervalSinceNow:0];

data.title = @"test";

等价于

 //字典
Data *data = [[Data alloc] initWithValue:@{@"time":[NSDate dateWithTimeIntervalSinceNow:0],@"title":@"test"}];

等价于

 //数组
 Data *data = [[Data alloc] initWithValue:@[[NSDate dateWithTimeIntervalSinceNow:0],@"test"]];

嵌套属性

Person *me = [[Person alloc] init];

Dog *myDog = [[Dog alloc] init];
myDog.name = @"myDog";
myDog.owner = me;

Dog *yourDog = [[Dog alloc] init];
yourDog.name = @"yourDog";
yourDog.owner = me;

me.name = @"crylown";
me.birthdate = [NSDate dateWithTimeIntervalSinceNow:1];

// 将dog添加到 <RLMArray>dogs属性中
[me.dogs addObject:myDog];
[me.dogs addObject:yourDog];

等价于

Dog *myDog = [[Dog alloc] init];
myDog.name = @"myDog";

Dog *yourDog = [[Dog alloc] init];
yourDog.name = @"yourDog";

Person *me = [[Person alloc] initWithValue:@[@"crylown",[NSDate dateWithTimeIntervalSinceNow:1],@[myDog,yourDog]]];

yourDog.owner = me;
myDog.owner = me;

等价于

// 多重嵌套
// dog.owner无法在这里设置
Person *me = [[Person alloc] initWithValue:@[@"crylown",[NSDate dateWithTimeIntervalSinceNow:1],@[@[@"myDog"],@[@"yourDog"]]]];

使用Realm进行数据管理

在数据管理的过程中,常用的方法有:

 RLMRealm *realm = [RLMRealm defaultRealm];

// 开放RLMRealm事务
[realm beginWriteTransaction];

// 在开放开放/提交事务之间进行数据处理

// 提交事务
[realm commitWriteTransaction];

等价于

[realm transactionWithBlock:^{

 // 进行数据处理

}];

添加数据

 RLMRealm *realm = [RLMRealm defaultRealm];

//    开放RLMRealm事务
[realm beginWriteTransaction];

//    添加到数据库 me为RLMObject
[realm addObject:me];

//    提交事务
[realm commitWriteTransaction];

查询数据

数据库查询

// 查询默认的 Realm 数据库
RLMResults *dogs = [Dog allObjects]; // 从默认的 Realm 数据库中,检索所有狗狗

如果有需要,也可以查询指定的数据库

// 查询指定的 Realm 数据库
RLMRealm *petsRealm = [RLMRealm realmWithPath:@"pets.realm"]; // 获得一个指定的 Realm 数据库
RLMResults *otherDogs = [Dog allObjectsInRealm:petsRealm]; // 从该 Realm 数据库中,检索所有狗狗

条件查询
1.使用断言字符串查询:

RLMResults *tanDogs = [Dog objectsWhere:@"color = ‘棕黄色‘ AND name BEGINSWITH ‘大‘"];

2.// 使用 NSPredicate 查询

NSPredicate *pred = [NSPredicate predicateWithFormat:@"color = %@ AND name BEGINSWITH %@",
                                                 @"棕黄色", @"大"];
RLMResults *tanDogs = [Dog objectsWithPredicate:pred];

3.链式查询

如果我们想获得获得棕黄色狗狗的查询结果,并且在这个查询结果的基础上再获得名字以“大”开头的棕黄色狗狗。

RLMResults *tanDogs = [Dog objectsWhere:@"color = ‘棕黄色‘"];
RLMResults *tanDogsWithBNames = [tanDogs objectsWhere:@"name BEGINSWITH ‘大‘"];

修改数据

内容直接更新

// author为数据库内RLMObject
[realm beginWriteTransaction];
author.name = @"托马斯·品钦";
[realm commitWriteTransaction];

根据主键更新
如果您的数据模型中设置了主键的话,那么您可以使用+[RLMObject createOrUpdateInRealm:withValue:]来更新对象,或者当对象不存在时插入新的对象。

// 创建一个带有主键的“书籍”对象,作为事先存储的书籍
Book *cheeseBook = [[Book alloc] init];
cheeseBook.title = @"奶酪食谱";
cheeseBook.price = @9000;
cheeseBook.id = @1;

// 通过 id = 1 更新该书籍
[realm beginWriteTransaction];
[Book createOrUpdateInRealm:realm withValue:cheeseBook];
[realm commitWriteTransaction];

键值编码
RLMObject、RLMResult 以及 RLMArray 都遵守键值编码(Key-Value Coding)(KVC)机制。

RLMResults *persons = [Person allObjects];

[[RLMRealm defaultRealm] transactionWithBlock:^{
  [[persons firstObject] setValue:@YES forKeyPath:@"isFirst"];
  // 将每个人的 planet 属性设置为“地球”
  [persons setValue:@"地球" forKeyPath:@"planet"];
}];

删除数据

删除某个在Realm数据库中的数据。

Book *cheeseBook = ... // 存储在 Realm 中的 Book 对象

// 在事务中删除一个对象
[realm beginWriteTransaction];
[realm deleteObject:cheeseBook];
[realm commitWriteTransaction];

删除数据库中的所有数据。

// 从 Realm 中删除所有数据
[realm beginWriteTransaction];
[realm deleteAllObjects];
[realm commitWriteTransaction];

数据排序

RLMResults 允许您指定一个排序标准,从而可以根据一个或多个属性进行排序。比如说,下列代码将上面例子中返回的狗狗根据名字升序进行排序:

// 排序名字以“大”开头的棕黄色狗狗
RLMResults *sortedDogs = [[Dog objectsWhere:@"color = ‘棕黄色‘ AND name BEGINSWITH ‘大‘"]
                         sortedResultsUsingProperty:@"name" ascending:YES];

数据库配置

一般地,我们使用的为默认的Realm数据库,即调用[RLMRealm defaultRealm]来初始化以及访问我们的realm变量。这个方法将会返回一个 RLMRealm对象,并指向您应用的 Documents (iOS) 或者 Application Support (OS X)文件夹下的一个名为“default.realm”的文件。

许多 Realm API 中的方法都支持两种默认的数据库访问方式,一种是RLMRealm实例,另一种是访问默认 Realm 数据库的便捷版本。例如 [RLMObject allObjects] 等同于 [RLMObject allObjectsInRealm:[RLMRealm defaultRealm]]。

Realm配置

通过RLMRealmConfiguration您可以配置诸如 Realm 文件在何处存储之类的信息。
配置同时也可以在每次您需要使用 Realm 实例的时候传递给[RLMRealm realmWithConfiguration:config error:&err],或者您也可以通过 [RLMRealmConfiguration setDefaultConfiguration:config] 来为默认的 Realm 数据库进行配置。
比如说,假设有这样一个应用,用户必须登录到您的网站后台才能够使用,然后您希望这个应用支持快速帐号切换功能。 您可以为每个帐号创建一个特有的 Realm 文件,通过对默认配置进行更改,就可以直接使用默认的 Realm 数据库来直接访问了,如下所示:

+ (void)setDefaultRealmForUser:(NSString *)username {
  RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];

  // 使用默认的目录,但是使用用户名来替换默认的文件名
  config.path = [[[config.path stringByDeletingLastPathComponent]
                   stringByAppendingPathComponent:username]
                   stringByAppendingPathExtension:@"realm"];

  // 将这个配置应用到默认的 Realm 数据库当中
  [RLMRealmConfiguration setDefaultConfiguration:config];
}

其他的Realm数据库

有的时候,在不同位置存储多个 Realm 数据库是十分有用的。 例如,如果您需要将您应用的某些数据打包到一个 Realm 文件中,作为主要 Realm 数据库的扩展。 您可以像以下代码这样做:

RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];

// 获取需要打包文件的路径
config.path = [[NSBundle mainBundle] pathForResource:@"MyBundledData" ofType:@"realm"];
// 以只读模式打开文件,因为应用数据包并不可写
config.readOnly = YES;

// 通过配置打开 Realm 数据库
RLMRealm *realm = [RLMRealm realmWithConfiguration:config];

// 从打包的 Realm 数据库中读取某些数据
RLMResults<Dog *> *dogs = [Dog objectsInRealm:realm where:@"age > 5"];

请注意,使用自定义路径来初始化 Realm 数据库需要拥有路径所在位置的写入权限。 通常存储可写 Realm 文件的地方是位于 iOS 上的“Documents”文件夹以及位于 OS X 上的“Application Support”文件夹。 具体情况,请遵循苹果的 iOS 数据存储指南, 它推荐将文件存储在<Application_Home>/Library/Caches目录下

错误处理

在数据的处理中可能会出现失败的情况,在查看错误的时候,有相关方法可以使用:
提交事务失败

[realm commitWriteTransaction:(NSError * _Nullable __autoreleasing * _Nullable)]

也可以使用

[realm transactionWithBlock:^{

} error:(NSError * _Nullable __autoreleasing * _Nullable)]

配置数据库失败

RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:&error];

要处理在指定线程中初次 Realm 数据库导致的错误, 给 error 参数提供一个 NSError 指针。

数据迁移

当您使用任意一个数据库时,您随时都可能打算修改您的数据模型。通过设置 RLMRealmConfiguration.schemaVersion 以及RLMRealmConfiguration.migrationBlock 可以定义一个迁移操作以及与之关联的架构版本。 迁移闭包将会提供提供相应的逻辑操作,以让数据模型从之前的架构转换到新的架构中来。 每当通过配置创建完一个 RLMRealm 之后,迁移闭包将会在迁移需要的时候,将给定的架构版本应用到更新 RLMRealm 操作中。
如下所示是最简单的数据迁移的必需流程:

// 在 [AppDelegate didFinishLaunchingWithOptions:] 中进行配置

RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
// 设置新的架构版本。这个版本号必须高于之前所用的版本号(如果您之前从未设置过架构版本,那么这个版本号设置为 0)
config.schemaVersion = 1;

// 设置闭包,这个闭包将会在打开低于上面所设置版本号的 Realm 数据库的时候被自动调用
config.migrationBlock = ^(RLMMigration *migration, uint64_t oldSchemaVersion) {
  // 目前我们还未进行数据迁移,因此 oldSchemaVersion == 0
  if (oldSchemaVersion < 1) {
    // 什么都不要做!Realm 会自行检测新增和需要移除的属性,然后自动更新硬盘上的数据库架构
  }
};

// 告诉 Realm 为默认的 Realm 数据库使用这个新的配置对象
[RLMRealmConfiguration setDefaultConfiguration:config];

// 现在我们已经告诉了 Realm 如何处理架构的变化,打开文件之后将会自动执行迁移
[RLMRealm defaultRealm];
时间: 2024-10-31 19:38:03

iOS开发-Realm数据库的相关文章

IOS开发之数据库FMDB

IOS开发之数据库FMDB 1.简介 需求作用:如果需要保存大量的结构较为复杂的数据时候, 使用数据库, 例如交规考试项目 常用的数据库: (1)Microsoft SQL Server 2000/2008:中小企业使用较多 (2)Oracle:比较复杂, 大企业使用较多 (3)Mysql数据库:网站使用较多 (4)sqlite:本地数据库, 访问数据足够快, 直接访问文件  足够简单, 功能相对其他数据库软件不是特别齐全, 足够用了  足够小, 系统不超过1M, 适合在移动端上使用 2. Me

iOS开发 - 网络&amp;数据库功能综述

学习经验尚浅,以前iOS开发一直停留在单机版的开发,但是现在如果一个移动端开发完全抛弃网络功能,它也不会存在很久.网上讲的关于iOS的网络部分都比较专一,这两天经过融合和总结,大致摸索出了一套整体流程,在此和对网络连接不甚明了的同学分享,本文不涉及技术层面,只是概念的串通. 前提注:如果你真的只是开发一个单机版app也或者公司已经将网络数据封装好给你个接口or XML格式等文件用而且也不想知道的话就请华丽丽地忽视我吧. 一.前提概览 首先,要考虑app所在的大环境是个什么级别的环境,我大致将环境

IOS开发——使用数据库

IOS开发——使用FMDB数据库 简介 需求作用: 如果需要保存大量的结构较为复杂的数据的时候,使用数据库,例如交规考试项目 1.数据库的基本介绍 数据库(DB)是一种数据模型组织起来并存放存储管理的数据仓库.它是由文件管理发展起来的,如今的数据库基本上都是关系型数据库. 数据库的基本操作是增.删.查.改. 常见的几种数据库,Oracle,Access,SQL Server,DB2,Mysql 手机上使用的数据库为SQLite,因为它占用资源很好,易于配置等原因. 2.mesaSQLite 使用

IOS开发-封装数据库sqlite3之为何选择FMDB

为什么使用第三方轻量级框架FMDB? FMDB是用于进行数据存储的第三方的框架,它与SQLite与Core Data相比较,存在很多优势. FMDB是面向对象的,它以OC的方式封装了SQLite的C语言API,使用起来更加的方便,不需要过多的关心数据库操作的知识. 为什么不使用core data和SQLite? Core Data是ORM的一种体现,实现了界面化操作.使用Core Data需要用到模型数据的转化,虽然操作简单,不需要直接操作数据库,但是性能没有直接使用SQLite高.但是SQLi

IOS开发之数据库FMDB的使用

本文中主要介绍ios数据库常用的软件以及常用的数据库操作方法. 1.数据库基本知识介绍 数据量小,结构简单,数据保存可采用归档,plist(xml格式),存进去的效率很低: 数据复杂,格式多,量大,用数据库存取效率高,比如交规考试项目的数据存储; 本地数据--->网络数据--->本地(一次取数据,多次取数据) 1.1常用数据库 (1).MicroSoft SQL Server ...2000/2008 中小企业使用较多 (2).Oracle,比较复杂,大企业使用较多 (3).Mysql 数据库

iOS开发之数据库的简单使用

数据库基础知识: plist:writetoFile,条件:只有一个对象拥有这个方法,才能使用plist存储,而且自定义对象不能用plist存储 Preference:偏好设置存储:NSUserDefault存储,好处:不需要关心文件名,快速存储,底层:就是用一个字典做存储.坏处:在iOS8之前,都必须做一下同步操作,目的让内存和硬盘同步. NSCoding(NSKeyedArchiver\NSkeyedUnarchiver):用来自定义对象归档,自定义对象需要归档:遵守NSCoding协议,并

iOS开发之数据库:增删改查

如何导入数据库? 首先要链接库,点击工程??选择Build Phases 下方有个Link Binary,点+ 搜索sqlite,选择libsqlite3.tbd ranh

iOS 开发之数据库(SQLite)

SQLite嵌入式数据库优点: 1.嵌入式数据库 2.支持事件,不需要配置,不需要安装,不需要管理员 3.支持大部分SQL92标准 4.完整的数据库保存在磁盘上面一个文件,同一个数据库文件可以在不同机器上面使用,最大支持数据库到2T 5.整个系统少于3万行,少于250KB的内存占用 开始使用SQLite: 1.引入头文件 2.打开数据库 3.执行SQL命令 4.关闭数据库 以下代码展示整个数据库的 打开.关闭.增加.删除.查找.修改. 创建一个单例: #import <foundation/fo

iOS开发中数据库常用的语句

一. 数据如何存入数据库! { 1.创建一张表.(根据存储的数据特点,创建对应的表!) 2.将数据存储在"表"中 } 二. 数据库使用 { 1. database(DB) File: 数据库文件路径! 数据库中的所有数据都保存在这个文件中! 数据库(SQL)语句是不区分大小写的! 如果是系统的关键字大写!自己的就用小写! 2. "表名"规范: 以 t_/T_ 开头,后面跟表名! 3. 插入数据! } DDL 语句 : "建表" 和 "删