That’s not what recordChangeTag was intended for so I had to look for another solution.
That solution was CloudKit’s Push Notifications. Basically, you register the app for notifications and the device will receive a notification each time CKRecord is updated (you can register for delete/creation notifs too).
That was great and all, but what do you do with that notification?
First, I don’t want to start a sync session in a background task. Downloading CKRecords in the background would be acceptable if they were small (<50KB) but they’re at least 3MB each. I also want to plan ahead and account for CKRecords with assets over 25MB each.
My goal from the start was to keep the sync engine as light-weight as possible, with minimal network transfers.
The other issue with background syncing is having to load the full sync engine as a background process, meaning far more overhead than necessary. Yes, these are artificial constraints I’ve placed on the project, and many apps on the App Store cram far more into a background task, but I digress.
The solution was to create a singleton class that keeps track of the CKRecordID.recordNames from the notification. I load the singleton, check to see if the recordID has been previously added, add it to an array if it hasn’t, then save to disk. The whole process is fast and lightweight. When the app resumes, I can download change to the records stored in the singleton, then clear the list.
Every decision comes with trade-offs. In a perfect world, I would sync changes in a background session. Of course it’s better for the user’s data to be up to date each time they open the app. But for the sake of battery life, mobile data usage, and overall performance of the OS, I think it’s the worth the user waiting 1-3 seconds for sync to complete. It’s a tradeoff I’m willing to make.
If you’ve read the previous 2 posts, updating the data for changes happens at the end of the sync session, after local offline changes are synced. In the spirit of doing the least amount of work possible, we sync inserts and deletions before changes. Consider this scenario - there are 5 total objects, 3 are on the client (synced previouslly), 2 new objects need to be downloaded from the server, one local object needs to be deleted, all objects have changes. If we synced the changes first, we would be updating the 3 local objects. Instead, we should complete the local deletion first, resulting in only updating the 2 remaining objects.
That didn’t explain the entire sync process but it illustrates the types of considerations you’ll have to make. Saving the user 5-10KB here and there doesn’t seem like much now, but after 1,000 syncs, it adds up.
What about insert/deletion notifications?
These are good for your typical CloudKit-based app where the data is online-only. For an app that allows the user to make offline changes, you need to handle this yourself.