Reputation: 14060
Let's say I save 50 records to CloudKit with a CKModifyRecordsOperation
like this:
let operation = CKModifyRecordsOperation(recordsToSave: records, recordIDsToDelete: nil)
operation.savePolicy = .changedKeys
operation.modifyRecordsCompletionBlock = { records, _, error in
//...
}
privateDB.add(operation)
On my other devices, I get sprayed with 50 different background notifications for each CKRecord
that changed. That's fine, I expect that.
I process each inbound notification like this:
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)
}
}
But since each of the 50 incoming notifications are separate events, this function gets called 50 different times, thus triggering a slew of requests to pull down the full records using the CKRecordID
s that the notifications give me.
How can I queue up all the incoming notification CKRecordID
s within a reasonable period of time so that I can make a more efficient CKFetchRecordsOperation
request with more than one recordID at a time?
Upvotes: 0
Views: 125
Reputation: 14060
I ended up using a timer for this, and it works quite well. Basically I start a timer when a new push notification comes in, and I reset it each time an additional notification arrives. Meanwhile, I collect all the CKRecordID
's that are coming in and then process them when the timer fires (which happens after the notifications stop flowing in).
Here's my code:
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)
}
}
}
Upvotes: 1