Realm 笔记(二)

RealmsSchema

系列文章目录:

  1. Realm 笔记 (一)
  2. Realm 笔记 (二)

第七章:Realm配置

打开一个Realm:let realm = try! Realm()

Realm没有使用单例,而是每次直接尝试新建一个Realm实例,有以下几个运行时优化:

  1. 调用Realm()返回同一个共享实例,而不受创建该Realm实例的线程限制。而Object和Realm实例被限制在创建的线程中,所以不能跨线程分享。
  2. Realm也提供了多个安全措施,如:使用不同的密钥或文件不存在均会报错。

书中均使用 try! ,但实际生产环境你可以进行错误处理。

deleteRealmIfMigrationNeeded 新版直接删除Realm文件,不做迁移处理。

存在文件在Documents文件夹有几个好处:自动备份到用户的iCloud storage,方便用户使用iTunes备份和访问。当然苹果推荐存储文件在Library文件夹。

App Bundle 文件夹是只读的,所以该目录中的Realm是能作为只读数据库。

加密在Realm极为简单,只要在配置中添加一个64位的密钥即可。

第八章:多个Realm和共享Realm

创建一个RealmProvider以方便操作Realm,尤其是涉及多个Realm或加密等情况。

img

如需转换JSON、CSV或纯文本为Realm,并内置到App Bundle。此时可以创建一个Target和来Tools.swift,自动生成Realm文件。把生成的Realm文件拖入Xcode即可。

img

第九章:依赖注入和测试

在本章中,您将学习两个重要主题:如何使用依赖注入来改进 Flash Cards 应用的架构,以及如何编写由Realm支持的同步和异步测试。

本章不会深入研究诸如测试驱动开发等主题,而是专注测试使用 Realm Object的类的技巧,并且依赖于特定于Realm的功能,例如更改通知。

测试 cards 场景(Scene)

  • CardsViewController:设置所需的手势识别器并根据用户的输入更新UI。本章不会介绍UI测试。
  • CardsModel:从Realm中抽象查询对象的简单封装。为它编写测试将意味着在测试中重复相同的代码并比较输出,而不提供实际值。除此之外,你真正要在这里测试的将是Realm的底层实现,它已经经过了充分测试。
  • CardsViewModel:实现此场景的业务逻辑。它格式化Model的输出,以显示在屏幕上,并提供与模型交互的方法。这将是一些单元测试的完美候选!

img

这里只是简单测试 ViewModel 初始化和更新状态。

img

测试 sets 场景

在显示列表的场景中,您的视图模型依赖于Realm通知来动态更新数据。你必须:

  • 模拟Realm框架以测试依赖通知的 ViewModel 和其他高级Realm功能。
  • 编写依赖Realm通知的测试

为了使测试有效,您需要稍微更改代码以提供一个方法将测试的 Realm providers 注入到Model和ViewModel中。

img

img

异步测试需要使用XCTestExpectation,这个期望类将帮助你等待某些条件在您的测试中得到满足,然后再转到您测试断言的部分。

在使用XCTWaiter类来持有测试的执行,直到满足期望为止。 XCTWaiter是Apple的XCTest框架中的一个便捷类,它暂时停止当前代码的执行,而不会阻塞当前线程。 XCTWaiter定期检查期望的状态,因此当异步代码将执行计数增加到3时,XCTWaiter将负责恢复执行测试。

步骤如下:

  • 初始化XCTestExpectation和expectedFulfillmentCount
  • 在异步回调中fulfill,
  • 最后添加定期检查结果的帮助类XCTWaiter。

img

测试 Word of Today 场景

img

小结:

在本章中,你将亲身体验用Realm编写同步和异步测试的简易性。本章中重点是:

  • 测试自己的逻辑,而不是Realm,因为它已经在全球数百万用户中得到了充分测试和使用。
  • “哑”模型和视图控制器可以更轻松地测试视图模型,您通常可以在其中放置MVVM应用程序的逻辑。
  • 编写需要这些依赖项的特定测试版本的测试时,使用中央provider结构来抽取某些依赖项的检索很有用。

通常,测试基于Realm的代码可能不会改变您构建自己的测试套件的方式。借助本章的经验,您应该能够为您的Realm项目编写可靠的测试,无论你心意哪一种架构。

注意:对于单元测试,模拟Realm本身是一个偏爱的问题。如果你想模拟Realm并从测试套件中删除Realm依赖关系,你可以模拟关键的方法,比如对象(^)、过滤器(^)等等。风险是你必须增加和保持的代码量,以保持与Realm自己行为的一致,尤其是已经有了基于内存的Realm这个特别棒的方案。

笔者觉得模拟Realm的唯一好处是,Realm依赖增加了CI服务器需要安装,构建和测试应用程序的时间。

第十章:高效率的多线程

Realm线程:多线程访问同一个Realm总是可以读写到最新的数据。

线程间传递Object,有以下两个替代方法:

  • 传递Object的主键
  • 使用ThreadSafeReference:let ref = ThreadSafeReference(to: myRealmObject)let myRealmobject = realm.resolve(ref)

主线程:访问带主键合适数量的数据时,无需担心性能问题。如在View Controller lifecycle 和 UIKit delegate 中直接读取Object,和更新UI。因为总是在同一个Realm文件的快照中工作,所以速度最快。

img

后台线程:(不推荐)由于是异步并发执行,会因为Realm 快照之间同步问题,产生性能和体积大的问题。

专用线程:(推荐)可以解决主线程影响UI,后台线程性能问题。使用Thread,自己维护一个线程的生命周期,所有读写都在该线程操作。还可以缓存任务批量提交读写事务,进一步提高性能。

img

img

简版(无缓冲机制)

img

未完待续…