Is is normal to end up with a LOT of changes on CKFetchRecordChangesOperation?

174 views Asked by At

I use CloudKit in my app, which seems to be working well. However when I initialise the app on a new device, using

CKFetchRecordChangesOperation *fetchRecordChangesOperation = [[CKFetchRecordChangesOperation alloc] initWithRecordZoneID:zoneID previousServerChangeToken:NIL];

I get a LOT of changes, as all previous deletions and changes appear to be synched across.

Is there a better way? for example to just download a full set of current data and set the serverChangeToken to the current value.

1

There are 1 answers

0
Edwin Vermeer On

When looking at the documentation of the CKServerChangeToken it looks like you can only get it when using the CKFetchRecordChangesOperation. See: https://developer.apple.com/library/prerelease/ios/documentation/CloudKit/Reference/CKServerChangeToken_class/index.html

So now how could you get a hold on that token:

Usually you will do something like this: As you can see in the CKFetchRecordChangesOperation you can initialize it with a previousServerChangeToken. This token works like a timestamp. When the operation completes, you get this token back in the fetchRecordChangesCompletionBlock. You have to save that token in for instance the user defaults. Then the next time you start a CKFetchRecordChangesOperation, you can use that token to start reading the changes since the last time you called it.

Actually saving the token can be a little tricky. I can suggest adding a property like this:

private var previousChangeToken: CKServerChangeToken? {
    get {

        let encodedObjectData = NSUserDefaults.standardUserDefaults().objectForKey("\(container.containerIdentifier)_lastFetchNotificationId") as? NSData
        var decodedData: CKServerChangeToken? = nil
        if encodedObjectData != nil {
            decodedData = NSKeyedUnarchiver.unarchiveObjectWithData(encodedObjectData!) as? CKServerChangeToken
        }
        return decodedData
    }
    set(newToken) {
        if newToken != nil {
            NSUserDefaults.standardUserDefaults().setObject(NSKeyedArchiver.archivedDataWithRootObject(newToken!), forKey:"\(container.containerIdentifier)_lastFetchNotificationId")
        }
    }
}

In your case you want a new application to start with a change token that could only have been created by an other running app. So besides saving the change token to the NSUserDefaults, you should also save it in CloudKit in the public Database in one specific settings recordType record. A newly installed app that does not have a token in it's NSUserDefaults can then read the token from your CloudKit settings record.