如何排队大量入站 CloudKit 通知

Posted

技术标签:

【中文标题】如何排队大量入站 CloudKit 通知【英文标题】:How to Queue Up Lots of Inbound CloudKit Notifications 【发布时间】:2018-08-05 06:17:04 【问题描述】:

假设我使用CKModifyRecordsOperation 将 50 条记录保存到 CloudKit,如下所示:

let operation = CKModifyRecordsOperation(recordsToSave: records, recordIDsToDelete: nil)
operation.savePolicy = .changedKeys

operation.modifyRecordsCompletionBlock =  records, _, error in
    //...


privateDB.add(operation)

在我的其他设备上,每更改一个 CKRecord,我都会收到 50 条不同的背景通知。没关系,我期待。

我这样处理每个入站通知:

func processCloudKitNotification(notification: CKNotification, database: CKDatabase)

  guard let notification = notification as? CKQueryNotification else  return 

  if let recordID = notification.recordID
    var recordIDs = [CKRecordID]()

    switch notification.queryNotificationReason 
      case .recordDeleted:
        //Delete [-]
        //...
      default:
        //Add and Edit [+ /]
        recordIDs.append(recordID)
    

    let fetchOperation = CKFetchRecordsOperation(recordIDs: recordIDs)

    fetchOperation.fetchRecordsCompletionBlock =  records, error in
      //...
    

    database.add(fetchOperation)
  

但由于 50 个传入通知中的每一个都是单独的事件,因此该函数会被调用 50 次不同的时间,因此会触发大量使用通知给我的CKRecordIDs 来拉取完整记录的请求。

如何在合理的时间内将所有传入的通知CKRecordIDs 排队,以便我可以一次使用多个记录ID 发出更有效的CKFetchRecordsOperation 请求?

【问题讨论】:

您是否真的在短时间内收到了 50 条通知?这些不应该合并吗?使用 CKFetchRecordZoneChangesOperation 怎么样? 我不确定通知是否应该合并。我很确定他们不会,因为后台推送的有效负载非常小。我在我的应用程序的其他地方使用了CKFetchRecordZoneChangesOperation,但是当回复CKNotification 时,我得到了CKRecordID 的更改内容,因此获取其相应记录似乎是有意义的。 【参考方案1】:

我最终为此使用了一个计时器,而且效果很好。基本上我会在收到新的推送通知时启动一个计时器,并在每次收到其他通知时重置它。同时,我收集所有传入的CKRecordID,然后在计时器触发时处理它们(这发生在通知停止流入之后)。

这是我的代码:

var collectNotificationsTimer: Timer?
var recordIDsFromNotifications = [CKRecordID]()

func processCloudKitNotification(notification: CKNotification, database: CKDatabase)

  guard let notification = notification as? CKQueryNotification else  return 
  guard let recordID = notification.recordID else  return 

  //:: 1 :: Collect record IDs from incoming notifications
  if notification.queryNotificationReason == .recordDeleted
    //Delete [-]
    //...
  else
    //Add and Edit [+ /]
    recordIDsFromNotifications.append(recordID)

    //:: 2 :: After collecting IDs for 1 second, request a batch of updated records
    collectNotificationsTimer?.invalidate()
    collectNotificationsTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: false) _ in

      let fetchOperation = CKFetchRecordsOperation(recordIDs: recordIDsFromNotifications)

      fetchOperation.fetchRecordsCompletionBlock =  records, error in
        recordIDsFromNotifications.removeAll()

        if let error = error 
          checkCloudKitErrorAndRetryRequest(name: "fetchRecordsCompletionBlock", error: error)
        else
          if let records = records
            //Save records...
          
        
      
      database.add(fetchOperation)
    
  

【讨论】:

以上是关于如何排队大量入站 CloudKit 通知的主要内容,如果未能解决你的问题,请参考以下文章

Swift CloudKit CoreData 远程更改通知也会触发本地更改

如何使用 CloudKit 的通知传递数据?

如何创建 CloudKit 订阅通知以触发记录属性更新?

当应用程序处于后台模式时,如何获得错过的 CloudKit 通知?

如何通知另一台设备 CloudKit 记录已更新?

如何更新 CloudKit 订阅