总体内容
1、Realm介绍
2、使用教程与辅助工具
3、Realm的具体使用
一、Realm介绍
- 1.1、Realm 是一个跨平台移动数据库引擎,支持
iOS
、OS X
(Objective-C
和Swift
)以及Android
,核心数据引擎C++
打造,并不是建立在SQLite之上的ORM, 是拥有独立的数据库存储引擎,具体详情。
ORM:对象-关系映射(OBJECT/RELATIONALMAPPING,简称ORM),ORM技术是在对象和关系之间提供了一条桥梁。
- 1.2、Realm性能:比
sqlite
,coredata
牛逼 - 1.3、Realm使用方面:相比于sqlite, coredata, 使用起来更加简单, 更易入门。
二、使用教程与辅助工具
- 2.1、Realm 教程
,打开后等待一下会自动转化为中文界面
在上面的教程里面我们可以看到有很多语言,我们关注的是 Swift
与 OC
,导入Realm方式如下:
- 导入方式一:CocoaPods 导入
- Swift
pod 'RealmSwift'
- OC
pod 'Realm'
建议在终端运行
pod repo update
以使CocoaPods最新的Realm版本。
pod install
失败解决方法:
- 首次(或者安装新版本)pod realm的时候,会下载sync-cocoa文件,这个文件有点大,所以pod install会很慢,且因身居404之内,所以易失败。手动下载可以加速 pod install
- 这里以10.2.1 版本为例:
pod 'RealmSwift', '10.2.1'
, 把 v10.2.0 替换为你对应realm的版本号即可:https://github.com/realm/realm-cocoa/blob/v10.2.0/dependencies.list
- 下面的 10.1.3 是上图的对应的:
REALM_SYNC_VERSION
curl https://static.realm.io/downloads/core/realm-core-10.1.3.tar.bz2 -o realm-core-10.1.3.tar.bz2 mkdir $TMPDIR/core_bin mv realm-core-10.1.3.tar.bz2 $TMPDIR/core_bin
- 然后进入项目,执行 pod install
- 导入方式二:手动导入,步骤如下
- <1>、下载 Realm 的最新发布版本,并解压;
根据自己的需要选择相应的
Realm.framework
- <2>、前往 Xcode 工程的 “General” 设置选项卡中,从
ios/dynamic/
、osx/
、tvos/
或者watchos/
目录中,将Realm.framework
拖曳到 “Embedded Binaries” 部分内。请确保勾选了 Copy items if needed(除非项目中有多个平台都需要使用 Realm ),然后单击 Finish按钮;
提示:在把
Realm.framework
拖进项目后一定要在TARGET
->General
->Embedded Binaries
里面把这Realm.framework
添加进来,否则运行会崩溃
- <3>、在单元测试目标的 “Build Settings” 中,将
Realm.framework
的父目录添加到 “Framework Search Paths” 部分中;
提示这一步一般在你把
Realm.framework
拖进项目就会自动完成
- <4>、如果使用了 Realm Swift,请将
Swift/RLMSupport.swift
文件拖曳到 Xcode 工程的文件导航栏中,请确保选中了 Copy items if needed 选择框; - <5>、如果在 iOS、watchOS 或者 tvOS 工程中使用 Realm,请在应用目标的 “Build Phases” 中创建一条新的 “Run Script Phase”,然后将下面这段代码粘贴到脚本文本框内:
bash "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/Realm.framework/strip-frameworks.sh"
添加后的效果:
- 因为要绕过 App Store 出现的提交 bug, 因此这一步在打包通用二进制文件时是必须的。
- 2.2、Realm 辅助工具
- <1>、Realm Browser: 可视化访问 Realm 数据库,与SqliteManger 打开 Sqlite数据库一样,Realm Browser 用来打开 Realm 数据库
<2>、Realm在xcode里面使用的插件Alcatraz(有点大),它 可以快速创建Realm可存储模型对象
下载后,打开运行一下
查看是否插件安装成功,创建一个类,滚到最下面看是否有如下图所示:
三、Realm的具体使用,Demo
3.1、简单的数据操作:使用 RLMRealm 对象, 保存指定模型
(1)、创建一个模型 Student继承于 RLMObject,看准了不是继承于 NSObject,如果在 2.2 里面安装了插件并运行后,插件生效,就可以快速创建 Realm的model了,如下图
- (2)、在Student类里面定义属性:由于Realm 在自己的引擎内部有很好的语义解释系统,所以 Objective‑C 的许多属性特性将被忽略,如nonatomic, atomic, strong, copy 和 weak 等。 因此为了避免误解,官方推荐在编写数据模型的时候不要使用任何的属性特性。
/** 学生的唯一ID */ @property int studentId; /** 学生的名字 */ @property NSString *studentName;
- (3)、创建对象的方式
- 方式一:普通创建
Student *student = [[Student alloc]init]; student.studentId = @1; student.studentName = @"小王";
- 方式二:通过父类
RLMObject
中的方法initWithValue
快速创建,可以放字典,也可以放数组,如下
// 数组 Student *student = [[Student alloc]initWithValue:@[@2,@"小冯"]; // 字典 Student *student = [[Student alloc]initWithValue:@{@"studentId":@2,@"studentName":@"小冯"}];
提示:放
数组
要与model
里面的属性顺序保持一致,放字典的话键值保持一致注意:所有的必需属性都必须在对象添加到 Realm 前被赋值
- (4)、使用
RLMRealm
对象, 保存指定模型,如下,我们采用initWithValue
快速创建并保存
// 获取RLMRealm对象 RLMRealm *realm = [RLMRealm defaultRealm]; // 创建对象 Student *student = [[Student alloc]initWithValue:@{@"studentId":@2,@"studentName":@"小冯"}];
- 保存模型方式一:开启事务,写入数据,关闭事务
// 开启事务 [realm beginWriteTransaction]; // 写入数据 [realm addObject:student]; // 关闭事务 [realm commitWriteTransaction];
- 保存模型方式二:使用 block
[realm transactionWithBlock:^{ [realm addObject:student]; }];
- 保存模型方式三
[realm transactionWithBlock:^{ [Student createInRealm:realm withValue:@{@"studentId": @3, @"studentName": @"王小二"}]; }];
提示:所有的必需属性都必须在对象添加到 Realm 前被赋值,并且使用 Realm 对象写入值保存模型
- 还可以开启线程来保存模型
- 3.2、使用
RLMRealm
对象, 更新指定模型
- 更新模型方式一:在事务中直接更新对象
Student *student = [[Student alloc]initWithValue:@{@"studentId":@3,@"studentName":@"王小二"}]; RLMRealm *realm = [RLMRealm defaultRealm]; // 保存模型 [realm transactionWithBlock:^{ // 写入数据 [realm addObject:student]; }]; // 更新模型:这里的更新模型一定是被realm所管理的模型 [realm transactionWithBlock:^{ // 写入数据 student.studentName = @"王冲"; }];
提示:上面的
student
已经被realm
所管理,而且已经和磁盘上的对象进行地址映射
- 更新模型一定是被
realm
所管理的模
- 更新模型方式二:根据 主键 进行更新
- (1)、上面的Student我们还没有设置主键,现在在
Student.m
里面设置一下 主键
/** 设置主键 */ +(NSString *)primaryKey{ return @"studentId"; }
- (2)、在事务中调用方法:
[realm addOrUpdateObject:stu2];
,如下
Student *student = [[Student alloc]initWithValue:@{@"studentId":@3,@"studentName":@"王小二"}]; RLMRealm *realm = [RLMRealm defaultRealm]; // 在事务里面做处理 [realm transactionWithBlock:^{ // 根据主键更新模型 [realm addOrUpdateObject:student]; }];
- 更新模型方式三:也是根据 主键 进行更新
- (1)、设置主键和上面的一样
- (2)、在事务中调用方法:
[模型类名 createOrUpdateInRealm:realm withValue:值];
,举例如下:
RLMRealm *realm = [RLMRealm defaultRealm]; [realm transactionWithBlock:^{ [Student createOrUpdateInRealm:realm withValue:@{@"studentId":@3,@"studentName":@"二蛋子"}]; }];
提示:withValue:后面还可以跟数组,但是传值要和模型里面属性的顺序一致,如:
[Student createOrUpdateInRealm:realm withValue:@[@3,@"二蛋子"]]; }];
- 3.3、Realm 删除模型数据 :删除的模型一定是 realm 所管理的
- 分析:我们要删除模型,首先要获取模型,不能是我们自己创建出来的模型,必须是从 realm 数据库里面获取出来的模型,如下:
- (1)、根据主键获取模型(结果只能是一个或者没有,所以直接用查询的模型接收)
Student *student = [Student objectForPrimaryKey:@2];
- (2)、通过sql 语句查询模型:因为根据名字查询的结果可能多个模型,采用 RLMResults 结果数组接收
RLMResults *results2 = [Student objectsWhere:@"studentName = '二傻'"];
- 删除方式一:删除单个模型
// 根据主键获取模型 Student *student = [Student objectForPrimaryKey:@2]; RLMRealm *realm = [RLMRealm defaultRealm]; // 删除单个模型 [realm transactionWithBlock:^{ [realm deleteObject:student]; }];
- 删除方式二:通过sql 语句查询模型:因为根据名字查询的结果可能多个模型
// 通过sql 语句查询模型:因为根据名字查询的结果可能多个模型 RLMResults *results2 = [Student objectsWhere:@"studentName = '二傻'"]; RLMRealm *realm = [RLMRealm defaultRealm]; // 删除查询出来的 模型 数组 [realm transactionWithBlock:^{ [realm deleteObjects:results2]; }];
当然你可以可以对
RLMResults
进行遍历删除或者for循环逐个删除,但是上面的删除还是挺方便的,Realm 内部做了遍历删除
- 删除方式三:删除某一特定类型的模型所有数据,如删除
Student
模型的所有数据
// 获取 Student 模型的所有数据 RLMResults *results = [Student allObjects]; RLMRealm *realm = [RLMRealm defaultRealm]; // 在事务里面删除模型里面的所有数据 [realm transactionWithBlock:^{ [realm deleteObjects:results]; }];
- 删除方式四: 删除
Realm
里面所有的模型数据(比如删除 Student、Dog 模型等等,全部数据删除)
RLMRealm *realm = [RLMRealm defaultRealm]; [realm transactionWithBlock:^{ [realm deleteAllObjects]; }];
提示:删除的操作一定要放到 事务里面,我一般采用block的事务方式,当然你可以选择其他的方式,如上面
3.1
中的(4)
- 3.4、 使用
RLMRealm
对象, 查询数据
- (1)、注意事项
- 所有的查询(包括查询和属性访问)在 Realm 中都是延迟加载的,只有当属性被访问时,才能够读取相应的数据。
解释:当我们在获取一个查询
RLMResults *results = [Student allObjects];
时,并没有读取到数据,当真正的操作数据的属性的时候才能够读取相应的数据。
- 查询结果并不是数据的拷贝:修改查询结果(在写入事务中)会直接修改硬盘上的数据。
解释:在我们查询一个模型后,所获取的数据不是拷贝出来的,而是直接操控数据库的
- 一旦检索执行之后, RLMResults 将随时保持更新
解释:在下面代码中第一次打印
results
会把数据库中的结果打印出来,当添加一个数据后,再次打印会把添加的数据和之前的数据都会打印出来,这就是所谓的:一旦检索执行之后, RLMResults 将随时保持更新
RLMResults *results = [Student allObjects]; NSLog(@"第 1 次打印结果:%@",results); Student *student = [[Student alloc]initWithValue:@{@"studentId":@1,@"studentName":@"小王"}]; RLMRealm *realm = [RLMRealm defaultRealm]; [realm transactionWithBlock:^{ [realm addObject:student]; }]; NSLog(@"第 2 次打印结果:%@",results);
- (2)、查询方式一:查询某一个模型的查询所有内容
RLMResults *results = [Student allObjects]; NSLog(@"打印结果:%@",results);
- (3)、查询方式二:条件查询(可以编辑自己需要的sql语句),更多的sql语句可以参考的的 Mysql的笔记,里面有更多的 sql 查询语句
RLMResults<Student *> *students = [Student objectsWhere:@"studentName = '小王'"]; NSLog(@"打印结果:%@",students);
- (4)、查询方式三:对查询结果排序
RLMResults<Student *> *students = [Student allObjects]; NSLog(@"没有排序的结果:%@",students); RLMResults *soreStudents = [students sortedResultsUsingKeyPath:@"studentId" ascending:YES]; NSLog(@"排序后的结果:%@",soreStudents);