15 Replies
      Latest reply on Jan 3, 2020 4:40 AM by andrewbuilder
      tschmitz Level 1 Level 1 (0 points)

        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.

        • Re: NSPersistentCloudKitContainer not syncing existing data
          tschmitz Level 1 Level 1 (0 points)

          Update: Filed a feedback report since this seems to be an issue others are encountering as well. (See https://www.andrewcbancroft.com/blog/ios-development/data-persistence/nspersistentcloudkitcontainer-buggy-behavior-list/)

          • Re: NSPersistentCloudKitContainer not syncing existing data
            m_bedwell Level 2 Level 2 (70 points)

            Just utilizing the container doesn't enable the sync.  You have to add/request the capabilities throuigh your plist file (iCloud under capabilities, may require background too, but i'm unsure).  Pretty sure you need remote notifications as well.  I read on a blog somewhere a step by step to get it working, but I haven't found 'Official' instructions for anything more than the class declaration yet.  I 'think' I googled NSPersistentCloudKitContainer and tutorial.. or maybe getting started. 

              • Re: NSPersistentCloudKitContainer not syncing existing data
                SpaceMan Level 1 Level 1 (10 points)

                You missed his point.  Data entereed after setting up NSPersistentCloudKitContainer synced.  It was pre-existing data which did not sync.  For a person with a core data app who wants to use CloudKit, this problem is huge.  And I'll bet that the original author signed up for remote notifications.  It's not that he didn't get a notification, he didn't get the data.

              • Re: NSPersistentCloudKitContainer not syncing existing data
                GLApps Level 1 Level 1 (0 points)

                I've got the same issue. 1000s of records in the existing Core Data database. All new data syncs perfectly, but the old data stays on just one device.

                 

                Do we need to do something to trigger the sync? Mark records for sync? Maybe iterate the records, and re-save each one?

                 

                We're at beta 5 now, and it still doesn't work. I'm beginning to think it's by design, not a bug.

                • Re: NSPersistentCloudKitContainer not syncing existing data
                  .Nick Apple Staff Apple Staff (40 points)

                  Do these records have entries in persistent history? Without them NSPersistentCloudKitContainer can't "see" the records.

                   

                  This is by design. However we will take your feedback reports on this issue as an enhancement request to make it easier to use NSPersistentCloudKitContainer with existing store files.

                   

                  Keep filing them. Include a sysdiagnose and the persistent store files if you can.

                    • Re: NSPersistentCloudKitContainer not syncing existing data
                      roelfromnieuwersluis Level 1 Level 1 (0 points)

                      Hi Nick, my existing CoreData container has no persitent history enabled. So existing records are not seen by NSPersitentCloudKitContainer. What would be a way to enable history tracking on those records to get them pushed to iCloud?

                      I can think of a 'hack' by adding a boolean flag to all entities and updating them once on the first launch with NSPersitentCloudKitContainer enabled, but that feels wrong.

                      • Re: NSPersistentCloudKitContainer not syncing existing data
                        andrewbuilder Level 1 Level 1 (0 points)

                        Nick, thanks for the input.

                         

                        Behaviours I've noticed...

                         

                        Scenario 1

                        Existing Core Data app with existing records.

                        Log in to the same Apple ID on different Simulators or Devices.

                        Enable NSPersistentCloudKitContainer and include container.viewContext.automaticallyMergesChangesFromParent = true

                        Only new records are synced to users CloudKit account and therefore across devices using the same Apple ID. Existing records remain only on the device on which they are created.

                         

                        Scenario 2

                        Existing Core Data app with existing records.

                        Log in to the same Apple ID on different Simulators or Devices.

                        Enable NSPersistentCloudKitContainer and include container.viewContext.automaticallyMergesChangesFromParent = true

                        Enable NSPersistentHistoryTrackingKey...

                                guard let containerStoreDescription = container.persistentStoreDescriptions.first else {

                                    fatalError("\(#function): Failed to retrieve a persistent store description.")

                                }

                                containerStoreDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)

                        ANY records entered with NSPersistentHistoryTrackingKey = true are synced to users CloudKit account and therefore across devices that are using the same Apple ID.

                        Records entered prior to setting NSPersistentHistoryTrackingKey = true are never synced to users CloudKit account and remain only on the device on which they are created..

                        If NSPersistentCloudKitContainer is switched to NSPersistentContainer, run a few times, then switched back to NSPersistentCloudKitContainer, even the previous records entered with NSPersistentHistoryTrackingKey = true are synced to users CloudKit account... in fact, so long as the CloudKit development environment is not reset, the app can be deleted from all devices and again, previous records entered with NSPersistentHistoryTrackingKey = true are synced to users CloudKit account and therefore across devices. To reiterate, any records entered prior to setting NSPersistentHistoryTrackingKey = true are never synced to users CloudKit account and remain only on the device on which they are created.

                        Note that I have found it is necessary to set NSPersistentHistoryTrackingKey = true when switching from NSPersistentCloudKitContainer back to NSPersistentContainer (only done for testing purposes during my efforts to sync existing records).

                         

                        Scenario 3

                        Existing Core Data app with no existing records.

                        Log in to the same Apple ID on different Simulators or Devices.

                        Enable NSPersistentCloudKitContainer and include container.viewContext.automaticallyMergesChangesFromParent = true

                        ALL records are synced to users CloudKit account and therefore across devices that are using the same Apple ID.

                        Unnecessary to separately enable NSPersistentHistoryTrackingKey.

                         

                        Some developers have suggested some interesting (and functional) workarounds. The most interesting to me is to set a bool for each existing record following the successful load of an NSPersistentCloudKitContainer. Toggling this bool for each record after loading the NSPersistentCloudKitContainer forces a sync for those existing records. While it is the best workaround I have stumbled upon so far, this also seems extremely cumbersome to me and I cannot bring myself to write the code to make this work.

                         

                        Surely there must be a mechanism to apply NSPersistentHistoryTrackingKey = true to all previous records? That is what I will be focussing on next, so any hints or guidance would be gratefully appreciated.