NSPersistentCloudKitContainer not syncing existing data

I'm running into trouble setting up sync using NSPersistentCloudKitContainer on an existing app. The app doesn't seem to sync data that was added to Core Data prior the app's iOS 13 update. For instance:


1. I install an existing, pre-iOS 13, version of the app and create several records that are stored in Core Data.

2. Over that existing install, I install the updated version that uses NSPersistentCloudKitContainer and create some additional new records.

3. I install the same new version on a second device.


Results: Records created in step 1 don't appear on the second device, but records created in step 2 do.


Is there a step I'm missing in order to get existing data to sync? I'm wondering if this has something to do with the persistent history token, but I'm unsure how to tell NSPersistentCloudKitContainer it should "start over" on first launch.

  • You will need to migrate your existing core data store with NSPersistentHistoryTrackingKey enabled. This will then allow your old data to be sync'd using NSPersistentCloudKitContainer.

  • I had the same issue and so I enabled both options description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey) description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)

    the issue still reproducible

Add a Comment

Replies

I tried the idea of adding a bool to each entity and toggling it, resulting in it getting written to CloudKit. This would work ok if the 2nd device started with no entities. In my case, the 2 devices each start with the same entities (via an earlier sync using a different method - dropbox). The result is then duplication of all of the entities as each device causes all of the entities to get written to CloudKit.

Has anyone looked at this solution: https://medium.com/@dmitrydeplov/coredata-cloudkit-integration-for-a-live-app-57b6cfda84ad? It involves copying everything over to a new context which seems a bit more drastic, but the author claims that it works completely. I tested it out and it does work - not sure what the merits are of this method or the ones mentioned above.

How the persistent history works and why it's needed? I read about the query generations, but fail to come up with a reasonable explanation why it prevents NSCloudKitContainer of syncing my objects. I was expecting to have the data persisted just by using NSPersistentContainer.


There's a method named record(for) documented in NSCloudKitContainer, which would return CKRecord for a given NSManagedObject. It can be seen in NSCloudKitContainer definition, when browsing to it with xcode, but the compiler can't see it. This would have helped to even see which NSManagedObjects have corresponding CKRecord, but no luck. I asked this previously on the CloudKit subforum and my post was just silently deleted there.


It's really hard to trust this not to lose/corrupt my data. If on local testing with a new app I (or you) can't explain why some records are not syncing, it's not very comforting.

If you add a bool, or a uuid in my case, then you will have double entities. But you can then delete any entity without a uuid (or bool) and that should sync to the other devices. I don't know this for sure, but it seems reasonable.
Any resolution to this issue?

I decode a large data set from a JSON file upon first run of my iOS app. Two simulator devices running on the same iCloud account credentials both "upload" their data set to the cloud although the sets are in all ways identical. A restart of each app shows double entries. Subsequently added data items are synced but not duplicated. Items have a UUID id which is identical between devices. Puzzling how to deliver the app with the desired large data set intact without causing duplicate entries. Is the toggle-a-boolean work-around the only way?