ioscocoa-touchcloudkitcksubscription

Do I need to delta fetch CloudKit changes as well as subscriptions?


I'm trying to implement CloudKit subscriptions. Previously I just fetch from a custom zone using CKServerChangeToken when my app starts and at key points in my app.

My setup purely uses a private database.

I'm just wondering if I still need to do this type of fetching if I move to using subscriptions? From the documentation I've seen it's not clear.

Rather than use a subscription query I'm using CKSubscriptionOptionsFiresOnRecordUpdate and looping round all my record types to register for notifications.


Solution

  • Yes, you still need to use a CKServerChangeToken even if you implement CKQuerySubscription. This is how a typical (from what I've seen) CloudKit app works to keep its data in sync:

    1. Fetch on Launch - When the app launches or becomes active again, check your CKServerChangeToken and fetch any new data.
    2. Fetch from Notifications - Update records from background (i.e. silent) push notifications as they come in from your record CKQuerySubscriptions so that your data fresh.

    Apple describes notifications as "best effort" which means sometimes they aren't going to arrive (and believe me, sometimes they don't). So I have found it useful to periodically fetch new changes (like every few minutes) just in case my app missed a change notification.

    Here is some sample code of how to register for all changes to a Task record type:

    let subscription = CKQuerySubscription(recordType: "Task", predicate: NSPredicate(value: true), subscriptionID: "subscriptionTask", options: [.firesOnRecordCreation, .firesOnRecordUpdate, .firesOnRecordDeletion])
    
    let info = CKNotificationInfo()
    info.shouldSendContentAvailable = true
    info.alertBody = "" //This needs to be set to improve notification priority
    subscription.notificationInfo = info
    
    let operation = CKModifySubscriptionsOperation(subscriptionsToSave: [subscription], subscriptionIDsToDelete: nil)
    operation.modifySubscriptionsCompletionBlock = { subscriptions, subscriptionIDs, error in
      //...
    }
    
    let container = CKContainer(identifier: "...")
    container.privateCloudDatabase.add(operation)
    

    I hope that helps.