Supporting CloudKit sync for SQLite is a daunting task. There are edge cases and nuances to be aware of, and the risk of introducing subtle bugs that cause data loss is very real.
Here’s the most important technique we used to build this feature…
Debugging the library by literally running multiple devices and editing data to see how it synchronizes is an absolute time suck. So we built our own in-memory version of CloudKit containers and databases so that we could interact with “CloudKit” in a testable and controllable manner.
This allowed us to write hundreds of tests for many intricate and subtle syncing situations (and turn bug reports from our beta users into failing tests), all without running on a real device or interacting with CloudKit:
• What happens when two devices edit the same record at the same time?
• What happens when a device receives a child record from CloudKit before it receives the parent record? Can foreign key constraints be enforced?
• What happens if a device receives a record from another device running an older version of the schema? Do we lose that data or can it be preserved until the device upgrades to the new schema?
• What happens on first launch of an existing app that has just added CloudKit synchronization? Can we upload all of the existing, local data to CloudKit?
• What happens to the user’s data when they are logged out of iCloud?
• What happens when a user writes to a shared record for which they do not have permissions?
• What happens when one device adds a child record to a parent record and another device deletes the parent record?
• What happens when a record in a shared zone is moved to another zone? Do all associated descendant get moved to the new zone too?
Whenever we wrote a passing test, we could immediately confirm the fix on-device using the live iCloud servers in place of our in-memory CloudKit.
And to be honestly, this is barely scratching the surface of what problems we came across while working on this and what we needed to write tests for.
See the full test suite here:
https://github.com/pointfreeco/sqlite-data/tree/main/Tests/SQLiteDataTests/CloudKitTests