Core Data + CloudKit > how to incorporate existing app data into new NSPersistentCloudKitContainer

My experience implementing Core Data + CloudKit has frankly been relatively easy and I feel very positive about the new NSPersistentCloudKitContainer.


Introduction and Thanks


Honestly, I approached the new implementation of Core Data + CloudKit with some trepidation.


My fears and anxiety were unfounded and I quickly learned just how (unsettlingly) easy it is to implement a CloudKit backed persistent store using NSPersistentCloudKitContainer.


The new Core Data documentation is the best I've read by Apple for many years, so a huge and sincere thank you to the Core Data team.


A couple of good posts on SO and a good blog by Andrew Bancroft helped close out my preliminary education... https://www.andrewcbancroft.com/blog/ios-development/data-persistence/getting-started-with-nspersistentcloudkitcontainer/


The sample app provided by Apple (per WWDC session 202: Using Core Data with CloudKit) is madness for a beginner, however I really appreciate the effort that has gone into demonstrating SO MANY capabilities of the frameworks and expect that in the future, I will refer to it more often.


Background


So I've successfully set up a couple of simple sample projects to begin to learn how this new service works.


With overwhelming relief and happiness, I've watched these sample projects run perfectly on Simulator (after I signed into iCloud using my developer Apple ID) and on device (using a different Apple ID).


To me this is extraordinary.


In the past, I have laboured for days in my unsuccessful and clumsy efforts to implement syncing across devices.


I'm developing an app, for some time now, but not yet released to the app store - so still in development but close to public testing. In other words... it was easy for me to target iOS 13 and not have to concern myself with backward compatibility.


I've even successfully implemented NSPersistentCloudKitContainer on this project... after I stripped out all my mostly failed previous attempts at CloudKit integration - pre iOS 13.


Problem


My Simulator and on device testing, cross referenced with CloudKit Dashboard, has shown that only new NSManagedObjects added to the NSPersistentCloudKitContainer are synced to the iCloud container as a CKRecord. Any existing local data remains in the persistent store, but is not pushed up.


  1. My app uses a large existing test data set that I'd much prefer to keep.
  2. I'd prefer to learn how to manage the process of loading an existing data set into the iCloud container for any possible future issues I might face.


So... I'm curious to know how to properly load a local store of existing data (NSMAnagedObjects) into the new NSPersistentCloudKitContainer so these are synced as CKRecords to the iCloud container?


Any advice please?

Replies

Try adding a UUID attribute to all of your entities in the model. You'll have to migrate, but that should be easy as it's only adding one attribute per entity. Then fetch every entity and add the UUID to every managed object. Then save. I have done this with a sample project and it seemed to work. You might want to try this on an experimental project first. Another way would be to have two managed object contexts and copy each one and save in the context with the CloudKit store. Although relationships are an issue.
  • Thanks for this - was really helpful. A quick question though - when you say add the UUID, I believe you don't mean the device UUID since each record needs it's own unique UUID ?

    So is this something you just randomly generate or is there some format to this ?

Add a Comment
Same here. There has got to be a better way of doing this.
My app is so old, the sqlite file is stored in the Documents directory and not the Library/"Application Support" directory as the new files are. I've created a struct for every entity in my core data and made the structs Codable. NSManagedObjects are not Codable. There were some issues as NSNumbers are not Codable, but I replaced those with Ints in the structures. I have written methods which stuff the structs from core data and have written methods which stuff the core data entities from the structs. I've also written methods to encode and decode the struct data using the JSON encoder/decoder. The plan is to grab the data from the old directory, put all of the core data objects into structs and then put the struct data into the new store file. That will sync the data. This will require a separate ManagedObjectContext for the old data. I also plan on saving the encoded data out for the user in iCloud Drive as backup files and will allow the user to restore their data from a backup file. Whew!
"Try adding a UUID attribute to all of your entities in the model. You'll have to migrate, but that should be easy as it's only adding one attribute per entity. Then fetch every entity and add the UUID to every managed object. Then save"

Thank you - that works. I also added a flag to the UserDefaults so this is only done once.