I've found a solution that works for my Core Data database - and mine is quite complex with multiple many-to-many relationships (A surgery/anaesthesia logbook app called Somnus)
I started by creating a new attribute for all my Core Data Entities called sentToCloud
and setting it to FALSE
by default in the Core Data model.
On the first load for an existing user:
- Fetch request using the predicate
"sentToCloud == FALSE"
for each Entity type
- Change
sentToCloud
to TRUE
for each Object then save the MOC
- This triggers
NSPersistentCloudKitContainer
to start syncing
I've done this in order of 'priority' that works for my database, assuming the iCloud sync sessions match the order in which Core Data is modified. In my testing this seems to be the case:
- I first sync all child (or most child-like) Entities
- Then sync their parents, and so on, up the tree
- I sync the Object the user interacts with last, once everything else is in place so the relationships are intact and they don't think their data is borked while we wait for
NSPersistentCloudKitContainer
to reconnect all the relationships
- I also leave any binary data (magically turned into a
CKAsset
behind-the-scenes) to last as it's not the most important part of my database
My database synced successfully from my iPad to iPhone and all relationships and binary data appear correct.
Now all I need is a way to tell the user when data is syncing (and/or some sort of progress) and for them to turn it off entirely.
ADDENDUM
So I tried this again, after resetting all data on the iCloud dashboard and deleting the apps on my iPhone & iPad.
Second time around it only synced some of the data. It seems like it still has a problem dealing with large sync requests (lots of .limitExceeded
CKErrors in the console).
What's frustrating is that it's not clear if it's breaking up the requests to try again or not - I don't think it is. I've left it overnight and still no further syncing, only more .limitExceeded
CKErrors.
Maybe this is why they don't want to sync existing data?
Personally, I think this is silly. Sometimes users will do a batch process on their data which would involve updating many thousands of Core Data objects in one action. If this is just going to get stuck with .limitExceeded
CKErrors, NSPersistentCloudKitContainer
isn't going to be a very good sync solution.
They need a better way of dealing with these errors (breaking up the requests into smaller requests), plus the ability to see what's going on (and perhaps present some UI to the user).
I really need this to work because as it stands, there is no way to synchronise many-to-many Core Data relationships using CloudKit.
I just hope that they're still working on this Class and improving it.