As I Learn CloudKit Syncing - Part 1: Asking Questions
- Use a custom
CKRecordZonein 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
- Custom zones allow you to create a
CKSubscriptionthat will notify clients of any changes to a zone, allowing the client to fetch the changes with the aforementioned
CKRecordhas support for serializing only the metadata fields for storage alongside the local record using
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
CKRecordbefore 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:
- Track local changes
- Send changes to the server
- Resolve conflicts
- Fetch server changes with
- Apply server changes
- 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.