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

未完待续…