As I Learn CloudKit Syncing - Part 1: Asking Questions

I described in the first part of this series, I’m adopting the “Little Data, Lots of Clients” CloudKit syncing strategy for syncing Qiktionary game data.

Both the Advanced CloudKit talk from 2014 and the CloudKit Tips and Tricks talk from this year cover how to use CloudKit in this way, but in a very high-level way:

  • Use a custom CKRecordZone in the user’s private database.
  • Custom zones support atomic modifications (only commit the changes if all changes can occur)
  • Custom zones also support fetching a “diff” of changes that have occurred since the last sync using the CKFetchRecordChangesOperation class
  • Custom zones allow you to create a CKSubscription that will notify clients of any changes to a zone, allowing the client to fetch the changes with the aforementioned CKFetchRecordChangesOperation
  • CKRecord has support for serializing only the metadata fields for storage alongside the local record using - encodeSystemFieldsWithCoder:.
  • CKRecord’s can be submitted back up to iCloud with just the metadata fields and fields that have changed. Which means you don’t have to fetch an entire CKRecord before updating it.

This seems to be the basic machinery useful in building CloudKit syncing. In Advanced CloudKit, they also layout a recipe to follow when performing a sync:

  1. Track local changes
  2. Send changes to the server
  3. Resolve conflicts
  4. Fetch server changes with CKFetchRecordChangesOperation
  5. Apply server changes
  6. Save server change token

One of the main strengths of CloudKit is how un-opinionated it is. As just a transport mechanism, it’s very flexible in how you structure your application and architecture. What this means though is that there is a lot more left to figure out on your own. At this point in the journey, here are all the things I’m left to figure out:

  • How do I track local changes? Should I hook into sqlite and listen for all changes made to the tables I’m syncing and create some sort of “changes” table. What does that table look like?
  • When do I perform a sync? At app launch? Every 60 seconds? Whenever anything changes? When the app is backgrounded?
  • What about when a record is deleted? I can’t just delete it from the local database anymore? Maybe that can go into the “changes” database too?
  • How do I deal with conflict errors when sending modifications to the server? Actually, the fact that CloudKit is making me answer this question is great, I should be forced to figure this one out. Core Data syncing suffered because it hid too much of this from the programmer.
  • What if iCloud is down? Or the device has a bad connection? Or the server is busy? Or iCloud rate limits me? Or there is no iCloud account? Or the user switches iCloud accounts? Or I’m sending too much data?
  • Since Qiktionary is already out, what kind of problems will I run into migrating people’s data when they first open the app after Qiktionary w/syncing is released? What if Qiktionary tries to do the initial import on both a person’s iPhone and iPad at the same time?
  • A whole other class of questions related to architecture and writing clean code. What’s the best way to go about that?
  • Also, for Qiktionary, this all has to corresponding to a Game Center account. So the local games are all syncing to iCloud under a certain GC account. If the user switches to a different GC account, the games don’t go along with them. This means they could be playing on multiple GC accounts on a single iCloud account. Question: How?
  • Zone Subscriptions are another concern. They aren’t 100% necessary but they should help to answer at least half of the “when do I sync” question. But they come with their own questions, like: when do I ask the user for permission to send them push notifications for this purpose? Is it a little silly to say hey I need your permission for push notifications because: sync?
  • How do I do this all in a way that doesn’t break other things, like duplicating games or lost games, overwriting games, scores, and achievements?

Since I am a couple of days into this now, I think I have a couple of these questions nailed down (I’ve even written some code so a few of those answers have survived that test), but many are still open questions, which I will trying to answer as this work (and this series) continues for the next couple of weeks.

Stay tuned for Part 2. Get notified of new posts by following me on Twitter. In the meantime download Qiktionary and learn some cool facts :).