开发过程记录
- 使用 URLNavigator 对路由进行模块化
- 在使用 URLNavigator 的基础上,利用 Swift 的特性,将路由定义成枚举,将路由类型化
- 路由的构造
- 自定义了一个
SchemaBuilder
, 可以进行链式调用构造路由模版和具体路由
- 自定义了一个
- 使用传统的 MVC, 但利用了 Realm 的通知特性,将大部分视图的更新操作通过订阅通知的方式进行
- 使用了路由组件,扩大了 ViewController 的灵活性,可以在根据路由对目标 ViewController 进行更多的定制,因此每个 ViewController 都实现了
Configurable
协议- 协议定义了一个构造方法,这个构造方法接受一个字典作为参数,将自定义的配置通过字典进行传递
- 而 Coordinator 也是实现了
Configurable
协议,可以复用对应 ViewController 的配置
- 针对关于列表的 ViewController, 其对应的 Coordinator 对实现一个
ListQueryCoordinatorable
协议- 该协议定义了一系列方法用于规范操作
- 列表数据初次获取的回调
- 列表数据有更新的回调
- 数据出错的回调
- 创建查询的方法
- 由于查询列表的操作规范了起来,因此,在需要用到列表数据的地方,都可以重用对应的 Coordinator, 配置好相关的回调即可
- 该协议定义了一系列方法用于规范操作
- 基本上,一个
UIViewController
对应一个 Coordinator, Coordinator 的作用- 负责与 Realm 通信,订阅 Realm 的消息,处理好需要变化的 UI 数据后回调视图更新的方法
- 负责提交,修改数据时的数据验证
- 对于数据库的操作,增删查改的操作类似,因此结合了范性,创建了一个
Repositorable
协议 - 利用 Swift 可以对 Protocol 提供默认实现的特性,将部分类似的数据库操作提供了默认实现
- 当某种类型的数据需要特定的操作时,就可以通过新增或重写的方法来提供
- 自定义了两个队列,分别用于对数据的读操作(
RealmReadingQueue
)和写操作(RealmWritingQueue
),便于 Debug
- 由于各种类型的 Repository 的使用频率非常高,可以说是在每个页面都涉及,因此,将 Repository 都设置成了单例,避免了 Repository 频繁创建对象
GCDWebServer
- 利用 GCDWebServer 创建一个简单的 RESTful API 服务,提供了
- 备份与恢复的接口
- 获取网页的静态文件接口
- 在电脑端通过网页访问设备上开启的服务,进行数据的下载与上传
- 电脑网页端使用 React 构建,将打包后的静态文件放到 App 的 Bundle 中
- 利用多线程多任务处理
- 多线程工具方面
- 使用 GCD 是最高效简单的方法,不用手动管理线程,但是任务的进度不可控,不能及时取消
- 使用比较底层的
Thread
过于多个任务来说,可以直接对任务进度进行管理,但线程方面的管理比较麻烦,容易出错 - 使用
Operation
, 由于Operation
是建立在 GCD 上,因此可以利用 GCD 的长处。同时Operation
提供了对任务的监听,可以对任务进行操作,并且可以设置任务间的依赖
- 创建了一个
ConcurrentableOperation
基本任务,提供并行特性 - 创建了一个
DataOperation
数据任务,继承于ConcurrentableOperation
,主要规范了数据任务的流程,构造方法(必须使用一个 URL 进行初始化,指定生成文件,读取文件的位置)
- 所有备份任务都是
ExportOperation
的子类,继承于DataOperation
- 规范了备份逻辑
- 将数据转换为二进制数据
- 将二进制数据转换为 JSON 数据
- 将 JSON 写入文件
- 针对每种类型的数据,可各自生成对应备份任务
- 所有恢复任务都是
ImportOperation
的子类,继承于DataOperation
- 规范了恢复逻辑
- 将备份文件(JSON)数据转换为 struct 类型数据
- 通过 struct 类型数据创建出 Realm 类型的对象
- 存入 Realm
- 针对每种类型的数据,可各自生成对应的恢复任务
- 任务进行过程中,遇到了错误,会立即取消其他的任务
- 备份或恢复的文件,源文件都是一个压缩文件,使用 SSZipArchive 进行解压缩操作
- 任务依赖
- 恢复任务
- 数据转换任务依赖解压任务
- 各类型数据间的关系恢复任务,依赖数据转换任务
- 数据库写入任务依赖数据间关系恢复任务
- 备份任务
- 压缩任务依赖所有数据文件生成任务
- 每个数据文件生成任务依赖数据转换任务
- 恢复任务
-
在上传文件时,使用 POST 方法,观察到会有
preflight OPTIONS response 501
的问题- 解决方法:在服务端创建响应
OPTIONS
方法,直接返回 200
- 解决方法:在服务端创建响应
-
跨域问题,在开发电脑网页端页面时,调用设备开启的服务
- 解决方法:服务端设置响应头部
Access-Control-Allow-Origin
- 解决方法:服务端设置响应头部
-
根据关键字搜索含有关键字的句摘和段摘,并高亮所有关键字
-
遇到问题
- 线程不一致
- Realm 支持从不同线程进行查询和写入,但从 Realm 生成的数据库操作对象(如 Results),只能在同一线程进行访问
- 因此,查找数据,与找出需要高亮数据的操作,需要在同一线程中进行
- 使用 GCD 是无法完成上述任务,因为使用 GCD 时,面向的是队列,而不是线程。GCD 本身维护着一个线程池,每一个任务的执行都不保证在同一个线程上
- 解决办法:在查询期间,使用 RunLoop 维护一个保活线程,保证期间的查询与高亮查找操作都在同一个线程,也避免每次关键字的修改都创建新的线程
- 模仿 Kingfisher 对 UIImage 扩展做法(包含特定的命名空间),自己实现了一个将与项目相关扩展归纳在某个命名空间下