Realm 笔记(二)
系列文章目录:
第七章:Realm配置
打开一个Realm:let realm = try! Realm()
Realm没有使用单例,而是每次直接尝试新建一个Realm实例,有以下几个运行时优化:
- 调用Realm()返回同一个共享实例,而不受创建该Realm实例的线程限制。而Object和Realm实例被限制在创建的线程中,所以不能跨线程分享。
- Realm也提供了多个安全措施,如:使用不同的密钥或文件不存在均会报错。
书中均使用 try! ,但实际生产环境你可以进行错误处理。
deleteRealmIfMigrationNeeded
新版直接删除Realm文件,不做迁移处理。
存在文件在Documents文件夹有几个好处:自动备份到用户的iCloud storage,方便用户使用iTunes备份和访问。当然苹果推荐存储文件在Library文件夹。
App Bundle 文件夹是只读的,所以该目录中的Realm是能作为只读数据库。
加密在Realm极为简单,只要在配置中添加一个64位的密钥即可。
第八章:多个Realm和共享Realm
创建一个RealmProvider以方便操作Realm,尤其是涉及多个Realm或加密等情况。
如需转换JSON、CSV或纯文本为Realm,并内置到App Bundle。此时可以创建一个Target和来Tools.swift,自动生成Realm文件。把生成的Realm文件拖入Xcode即可。
第九章:依赖注入和测试
在本章中,您将学习两个重要主题:如何使用依赖注入来改进 Flash Cards 应用的架构,以及如何编写由Realm支持的同步和异步测试。
本章不会深入研究诸如测试驱动开发等主题,而是专注测试使用 Realm Object的类的技巧,并且依赖于特定于Realm的功能,例如更改通知。
测试 cards 场景(Scene)
- CardsViewController:设置所需的手势识别器并根据用户的输入更新UI。本章不会介绍UI测试。
- CardsModel:从Realm中抽象查询对象的简单封装。为它编写测试将意味着在测试中重复相同的代码并比较输出,而不提供实际值。除此之外,你真正要在这里测试的将是Realm的底层实现,它已经经过了充分测试。
- CardsViewModel:实现此场景的业务逻辑。它格式化Model的输出,以显示在屏幕上,并提供与模型交互的方法。这将是一些单元测试的完美候选!
这里只是简单测试 ViewModel 初始化和更新状态。
测试 sets 场景
在显示列表的场景中,您的视图模型依赖于Realm通知来动态更新数据。你必须:
- 模拟Realm框架以测试依赖通知的 ViewModel 和其他高级Realm功能。
- 编写依赖Realm通知的测试
为了使测试有效,您需要稍微更改代码以提供一个方法将测试的 Realm providers 注入到Model和ViewModel中。
异步测试需要使用XCTestExpectation,这个期望类将帮助你等待某些条件在您的测试中得到满足,然后再转到您测试断言的部分。
在使用XCTWaiter类来持有测试的执行,直到满足期望为止。 XCTWaiter是Apple的XCTest框架中的一个便捷类,它暂时停止当前代码的执行,而不会阻塞当前线程。 XCTWaiter定期检查期望的状态,因此当异步代码将执行计数增加到3时,XCTWaiter将负责恢复执行测试。
步骤如下:
- 初始化XCTestExpectation和expectedFulfillmentCount
- 在异步回调中fulfill,
- 最后添加定期检查结果的帮助类XCTWaiter。
测试 Word of Today 场景
小结:
在本章中,你将亲身体验用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文件的快照中工作,所以速度最快。
后台线程:(不推荐)由于是异步并发执行,会因为Realm 快照之间同步问题,产生性能和体积大的问题。
专用线程:(推荐)可以解决主线程影响UI,后台线程性能问题。使用Thread,自己维护一个线程的生命周期,所有读写都在该线程操作。还可以缓存任务批量提交读写事务,进一步提高性能。
简版(无缓冲机制)
未完待续…