如何给ios中的nssdictionary中添加一个模型对象

原标题:iOS 数据持久化方案-Relm的使用

2、使用教程与辅助工具

1.1、Relm 是一个跨平台移动数据库引擎支持iOS、OS X(Objective-C和Swift)以及ndroid,核心数据引擎C++打造并不是建立在SQLite之上的ORM, 是拥有独立的数据庫存储引擎,具体详情

二、使用教程与辅助工具

打开后等待一下会自动转化为中文界面

在上面的教程里面我们可以看到有很多语言,我們关注的是 Swift 与 OC,导入Relm方式如下:

导入方式二:手动导入步骤如下

提示这一步一般在你把 Relm.frmework 拖进项目就会自动完成

因为要绕过 pp Store 出现的提交 bug, 因此这一步在打包通用二进制文件时是必须的

查看是否插件安装成功,创建一个类滚到最下面看是否有如下图所示:

3.1、简单的数据操作:使用 RLMRelm 对象, 保存指定模型

(1)、创建一个模型 Student继承于 RLMObject,看准了不是继承于 NSObject,如果在 2.2 里面安装了插件并运行后,插件生效就可以快速创建 Relm的model了,如丅图

(2)、在Student类里面定义属性:由于Relm 在自己的引擎内部有很好的语义解释系统所以 Objective?C 的许多属性特性将被忽略,如nontomic, tomic, strong, copy 和 wek 等 因此为了避免误解,官方推荐在编写数据模型的时候不要使用任何的属性特性

(3)、创建对象的方式

方式二:通过父类 RLMObject 中的方法 initWithVlue 快速创建,可以放字典,也可以放数组如下

提示:放数组要与 model 里面的属性顺序保持一致,放字典的话键值保持一致

注意:所有的必需属性都必须在对象添加到 Relm 前被赋值

保存模型方式一:开启事务写入数据,关闭事务

保存模型方式二:使用 block

示:所有的必需属性都必须在对象添加到 Relm 前被赋值并且使用 Relm 對象写入值保存模型

还可以开启线程来保存模型

更新模型方式一:在事务中直接更新对象

//更新模型:这里的更新模型一定是被relm所管理的模型

提示:上面的 student 已经被 relm 所管理,而且已经和磁盘上的对象进行地址映射

更新模型一定是被 relm 所管理的模型

更新模型方式二:根据 主键 进行更噺

(1)、上面的Student我们还没有设置主键现在在 Student.m 里面设置一下 主键

更新模型方式三:也是根据 主键 进行更新

(1)、设置主键和上面的一样

3.3、Relm 删除模型數据 :删除的模型一定是 relm 所管理的

分析:我们要删除模型,首先要获取模型不能是我们自己创建出来的模型,必须是从 relm 数据库里面获取絀来的模型如下:

(1)、根据主键获取模型(结果只能是一个或者没有,所以直接用查询的模型接收)

(2)、通过sql 语句查询模型:因为根据名字查询嘚结果可能多个模型采用 RLMResults 结果数组接收

删除方式一:删除单个模型

// 根据主键获取模型

删除方式二:通过sql 语句查询模型:因为根据名字查詢的结果可能多个模型

// 通过sql 语句查询模型:因为根据名字查询的结果可能多个模型

// 删除查询出来的 模型 数组

当然你可以可以对 RLMResults 进行遍历删除或者for循环逐个删除,但是上面的删除还是挺方便的Relm 内部做了遍历删除

删除方式三:删除某一特定类型的模型所有数据,如删除 Student 模型的所有数据

// 在事务里面删除模型里面的所有数据

删除方式四: 删除 Relm 里面所有的模型数据(比如删除 Student、Dog 模型等等全部数据删除)

提示:删除的操莋一定要放到 事务里面,我一般采用block的事务方式当然你可以选择其他的方式,如上面 3.1 中的 (4)

所有的查询(包括查询和属性访问)在 Relm 中都是延迟加载的只有当属性被访问时,才能够读取相应的数据

解释:当我们在获取一个查询 RLMResults *results = [Student llObjects]; 时,并没有读取到数据当真正的操作数据的屬性的时候才能够读取相应的数据。

查询结果并不是数据的拷贝:修改查询结果(在写入事务中)会直接修改硬盘上的数据

解释:在我們查询一个模型后,所获取的数据不是拷贝出来的而是直接操控数据库的

一旦检索执行之后, RLMResults 将随时保持更新

解释:在下面代码中第一次咑印 results会把数据库中的结果打印出来,当添加一个数据后再次打印会把添加的数据和之前的数据都会打印出来,这就是所谓的:一旦检索執行之后, RLMResults 将随时保持更新

(2)、查询方式一:查询某一个模型的查询所有内容

(3)、查询方式二:条件查询(可以编辑自己需要的sql语句)更多的sql語句可以参考的的 Mysql的笔记,里面有更多的 sql 查询语句

(4)、查询方式三:对查询结果排序

(5)、查询方式四:链式查询 (在查询结果的基础上, 进行二次查詢)

(6)、查询方式五:分页 查询,先看一个基础知识更多的可以看我的 数据库查询的第五部分

数据库分页查询的基础知识

Relm官网关于分页的讲解

我们在这里采用先拿到相应条件下的数据,再根据分页(利用for循环)来展示数据

比较操作数可以是属性名称或常量至少有一个操作数必须是属性名称。

布尔属性支持比较运算符==和!=

对于NSString属性,LIKE运算符可用于将左手属性与右手表达式进行比较:?并且允许作为通配符其Φ?匹配1个字符并匹配0个或更多个字符。示例:vlue LIKE '?bc*'匹配“bcde”和“cbc”等字符串

字符串的变音符号不敏感比较,例如nme BEGINSWITH[d] 'e'匹配étoile此修饰符可与[c]修饰苻组合使用。(此修饰符只能应用于Relm支持的字符串子集:请参阅详细信息的限制)

子查询受以下限制支持:

@count是唯一可以应用于SUBQUERY表达式的運算符。

尚不支持相关的子查询

不支持集合类型,比如:NSSrry 不能直接存储

(2)、不支持集合类型的解决方案

(3)、比如:存储 imge图片我们不能直接存储 UIImge,我们可以存储 NSDt,如下定义

在学生 Student 里面定义狗数组如下

(1)、对一关系:多对一或一对一关系

比如一个学生有一只狗,那么我们就可以在學生里面定义一个狗的属性如下

在使用的时候和其他的属性一样,正常的赋值即可

对一关系:多对一或一对一关系

举例:一个学生有多呮狗那么我们需要在学生里面定义一个狗的数组,但是这个数组格式有一定要求在狗的类.h里面遵守 RLM_RRY_TYPE(Dog),一般在安装了插件后在创建model的时候僦会自动遵守这个协议

在学生里面定义狗数组,如下

使用的时候给小明两只狗

(3)、反向关系:关系是单向的。就拿我们的两个类Student并Dog作为┅个例子。如果Student.dogs链接到Dog实例则可以按照链接从Student 到 Dog,但是无法从 Dog到其Student对象您可以设置Dog.owner链接到的一对一属性Student,但这些链接彼此独立添加┅个Dog to Student.dogs不会将该狗的Dog.owner属性设置为正确Student。为解决此问题Relm提供链接对象属性以表示反向关系。

上面 linkingObjectsProperties 方法里面第一个参数是类对象第二个是相應类里面的属性,通过链接对象属性您可以从特定属性获取链接到给定对象的所有对象。一个Dog对象可以有一个名为属性owners包含所有的Student有这個确切的对象Dog在他们的对象dogs属性创建owners类型的属性,RLMLinkingObjects然后覆盖+[RLMObject

在使用的时候如下,通过 Dog 查询其主人的信息

在使用的时候,如下,通过 Dog 查询其主人的信息

(1)、可空属性:默认情况下, 属性值可空, 如果强制要求某个属性非空, 可以使用如下方法,比如我们要num属性必须有值,可以在像一个嘚model的.m 如下设置,在保存模型的时候如果不赋值会报错的

(2)、默认值:我们在给一些属性赋值的时候,如果不赋值我们想有一个默认的值,鈳以在相应的model的.m里面的下面方法设置对应属性的值如下

忽略属性一:使用 redonly 来忽略这个属性,也就是不用写入数据库如下

忽略属性二:茬对应model 的 .m里面设置,如下

可以注册侦听器以接收有关Relm或其实体的更改的通知当Relm作为一个整体被更改时发送领域通知 ; 更改,添加或删除单個对象时会发送收集通知

只要对返回的通知令牌进行引用,就会传递通知您应该在注册更新的类上保留对此标记的强引用,因为在取消分配通知令牌时会自动取消注册通知

通知始终在最初注册的线程上提供。该线程必须具有当前运行的运行循环如果您希望在主线程鉯外的线程上注册通知,则您负责在该线程上配置和启动运行循环(如果尚不存在)

在提交每个相关的写事务之后异步调用通知处理程序,无论写事务发生在哪个线程或进程上

如果在启动写入事务时将Relm提升到最新版本,则可能会同步调用通知处理程序如果在Relm进入最新蝂本时,将以触发通知的方式修改或删除正在观察的Relm实体则会发生这种情况。此类通知将在当前写入事务的上下文中运行这意味着尝試在通知处理程序中开始写入事务将导致Relm抛出异常。如果您的应用程序的架构设置可能会出现这种情况您可以使用它-[RLMRelm

由于使用运行循环傳递通知,因此运行循环上的其他活动可能会延迟通知的传递当无法立即传递通知时,多个写入事务的更改可能会合并为单个通知

(2)、領域通知:通知处理程序可以在整个Relm上注册。每次提交涉及该Relm的写入事务时无论写入事务发生在哪个线程或进程上,都将触发通知处理程序:

创建一个强引用通知对象

收集通知不会收到整个Relm而是收到细粒度的更改说明。它们包括自上次通知以来已添加删除或修改的对潒索引。收集通知是异步传递的首先是初始结果,然后是每次写入事务后再次发送这会改变集合中的任何对象(或添加新对象)。

前兩个删除和插入,在对象开始和停止成为集合的一部分时记录索引这会将对象添加到Relm或从Relm中删除它们时考虑在内。为此RLMResults当您筛选特萣值并更改对象以使其现在与查询匹配或不再匹配时也适用。对于基于RLMrry或RLMLinkingObjects包括派生的集合RLMResults当在关系中添加或删除对象时,这也适用

只偠集合中对象的属性发生更改,您就会收到有关修改的通知这也发生更改的一对一和一对多的关系,虽然通知不会采取反向关系考虑在內

创建一个强引用通知对象

提示:results并不一定是全部的数据,你可以通过查询去获取一些数据当这个结果集的数据发生变化就会走这个通知

举例2:我们可以看如果在tbleview上面的数据变化时候的代码

Relm支持对象级通知。您可以在特定Relm对象上注册通知以便在删除对象时或在对象上嘚任何托管属性修改其值时收到通知。(这也适用于将其值设置为其现有值的托管属性)

只有Relm管理的对象可能在其上注册了通知处理程序。

对于在不同线程或不同进程中执行的写入事务当管理对象的Relm(自动)刷新到包含更改的版本时,将调用该块而对于本地写入事务,它将在某个时刻被调用写入事务提交后的未来。

通知处理程序有三个参数第一个参数deleted是BOOL指示对象是否已删除。如果是这样YES其他参數将为nil,并且永远不会再次调用该块

第二个参数,chnges是一个NSrry的RLMPropertyChnge对象这些对象中的每一个都包含已更改的属性的名称(作为字符串),前┅个值和当前值

第三个论点是NSError。如果发生涉及对象的错误NSError则将包含有关发生的事件的信息,chnges将为nildeleted将是NO,并且将永远不再调用该块

3.9、Relm数据库操作 (不同的用户, 使用不同的数据库文件)

(1)、不同的用户, 创建不同的数据库(用户在登陆后,我们就进行设置相应的数据库dtbseNme 是数据库嘚名字,以 .relm 结尾)

// 使用默认的目录但是使用用户名来替换默认的文件名

// 将这个配置应用到默认的 Relm 数据库当中

不同的用户, 创建不同的数据库

(2)、只读数据库的设置

// 以只读模式打开文件,因为应用数据包并不可写

(3)、删除指定用户的数据库

3.10、Relm 数据库迁移(适用于修改了数据模型的情況)

(1)、适用于修改了数据模型的情况:比如在一个模型里面我们删除了一个属性或者添加了一个属性的情况等等结构发生了变化

// 2. 叠加版夲号(要比上一次的版本号高) 0

// 3. 设置闭包,这个闭包将会在打开低于上面所设置版本号的 Relm 数据库的时候被自动调用

// 什么都不要做!Relm 会自行检测噺增和需要移除的属性然后自动更新硬盘上的数据库架构

// 4. 让配置生效(告诉 Relm 为默认的 Relm 数据库使用这个新的配置对象)

// 5. 我们已经告诉了 Relm 如哬处理架构的变化,打开文件之后将会自动执行迁移,数据结构会发生变化

(3)、数据迁移(比如说想要把某些数据用其他的数据字段表示我們可以在上面代码的block做操作)

// 无需做任何事情, 就可以完成, 数据结构, 以及数据的迁移

(4)、属性重命名(上面代码的block做操作)

(5)、多版本增量式迁迻(线性迁移)

假如说,我们的应用有两个用户:JP和TimJP经常更新应用,但Tim却经常跳过某些版本所以JP可能下载过这个应用的每一个版本,并且┅步一步地跟着更新构架:第一次下载更新后数据库架构从v0更新到v1;第二次架构从v1更新到v2 …以此类推,井然有序相反,Tim很有可能直接从v0蝂本直接跳到了v2版本因此,应该您使用非嵌套的 if (oldSchemVersion < X)结构来构造您的数据库迁移模块以确保无论用户在使用哪个版本的架构,都能完成必需的更新

当你的用户不按套路出牌,跳过有些更新版本的时候另一种情况也会发生。假如您在v2里删掉了一个“emil”属性然后在v3里又把咜重新引进了。假如有个用户从v1直接跳到v3那Relm不会自动检测到v2的这个删除操作,因为存储的数据架构和代码中的架构吻合这会导致Tim的人對象有一个v3的电子邮件属性,但里面的内容却是v1的这个看起来没什么大问题,但是假如两者的内部存储类型不同(比如说:从ISO emil标准格式變成了自定义格式)那麻烦就大了。为了避免这种不必要的麻烦我们推荐您在if (oldSchemVersion < 3)语句中,清空所有的电子邮件属性

// 只有当 Relm 数据库的架構版本为 0 或者 1 的时候,才添加“emil”属性

// 只有当 Relm 数据库的架构版本为 2 的时候去掉“emil”属性

说一下 Relm 使用的话对项目会植入很深,因为它创建嘚model 都是继承于RLMObject,相应模型里面的数组也是 RLMrry 类型我们可以看出如果在项目去掉Relm是一件很麻烦的事情,但是它的功能是很强大的;前面面我们所学的 iOS Sqlite数据库的使用 对项目的植入很小功能不是很强大,基本上够用;具体用什么自己决定了

  • 1.字典跟模型的优缺点比较: 1>字典茬使用key的时候Xcode不会有提示容易出错,模型就不会 2>①所谓模型...

  • 用模型取代字典数组的好处 使用字典的弊端 一般情况下设置字典数据和取出芓典数据都得使用字符串类型的"key"编写...

  • *7月8日上午 N:Block :跟一个函数块差不多,会对里面所有的内容的引用计数+1想要解决就用__block...

  • 企业合理避税规萣是允许的,但是偷税漏税却不行两者之间存在性质的差异,所以企业合理避税一定要注意有哪些事犯了将被...

我要回帖

更多关于 nss+ 的文章

 

随机推荐