Listify 云同步模块的改进

August 3, 2019
iOSListifyCloudKit

在以前的文章 Listify 的iCloud云同步功能开发笔记 里,我介绍了一些 CloudKit 的入门知识。文章提到的内容是从 Listify 云同步开发中总结而来。近期随着归档功能的加入,Listify 需要同步的项目变得多了起来,这篇文章将会补充一些上次没有说的特别详细的地方。

前些日子为 Listify 加入了归档功能,归档功能将会保存用户创建的所有清单条目。在之前的版本中,Listify 只会同步有效的条目,已经完成的并且删除条目会被直接删除,所以每次不管是拉取还是推送的 CKRecord 保守估计不会超过50个,因为几乎不会有人会像 Listify 添加50个条目在主界面上而不去做。因为归档功能会记录所有历史的条目,这可能使得某次需要同步的数据量变得很大,假设我一天会产生5个新的todo,那么一年下来会有大概2000多个条目存在 Listify 的todo数据库和iCloud中,当我换了一个手机重新安装 Listify 之后,Listify 需要一次性将这2000个条目拉取回来,这样的话一次拉取是不够的,反之,如果一次要推送 2000 个 CKRecord 到 iCloud 服务器上也是不行的。

数据拉取

之前文章讲过,拉取数据使用的是一个 CKFetchRecordZoneChangesOperation, 这个Operation实例会根据Token来拉取服务器和本地不同的 CKRecord,实现这个实例的时候还要实现一个 recordZoneFetchCompletionBlock 的闭包函数,这个函数是这么定义的:

  1. var recordZoneFetchCompletionBlock: ((CKRecordZone.ID, CKServerChangeToken?, Data?, Bool, Error?) -> Void)? { get set }

回调参数的第四个为一个叫做 moreComing 的布尔值,当执行这个回调的时候,如果拉取的数据过多,服务器为了保证网络性能只会返回一部分 CKReord ,在这个时候,moreComing 会被设置为 true,如果发现这个值为 true的话则需要再发起一个新的 CKFetchRecordZoneChangesOperation 请求,直到闭包的 moreComing 变为 false则代表数据已经拉取完成。
更多可以查看 Apple 的文档 recordZoneFetchCompletionBlock - CKFetchRecordZoneChangesOperation | Apple Developer Documentation

数据推送

拉取过后需要将新的数据推送到 iCloud 的 database 中,需要使用 CKModifyRecordsOperation,在之前的文章也介绍过,CKModifyRecordsOperation 在推送大量 CKRecord 的时候会出现 CKError.Code.limitExceeded 错误,在官方的文档中也提到了,给出了一般最多一次推送 400 个 CKRecord,所以建议每次推送的时候把数据分割成小于 400 长度的若干个子列表,然后使用多个 CKModifyRecordsOperation 上传。

可以对Array类添加一个chunked函数来进行分割:

  1. extension Array {
  2. func chunked(into size: Int) -> [[Element]] {
  3. return stride(from: 0, to: count, by: size).map {
  4. Array(self[$0 ..< Swift.min($0 + size, count)])
  5. }
  6. }
  7. }

Comments

July 21, 2018 at 10:52 am

There are no comments

keyboard_arrow_up