7

I followed the same steps as in "Using Core Data With CloudKit":

  1. New project
  2. Enable Core Data + Cloud Kit
  3. Add iCloud/CloudKit entitlement + Background mode/remote notifications entitlement.
  4. In the iPhone Xr simulator I signed into an iCloud account I created (and then verified on icloud.com!) and ran the app, creating multiple entries.
  5. I then signed into the same iCloud account in the iPhone Xs simulator. I ran the app but no entries were merged. Creating entries in this simulator also does not merge back over to the Xr simulator.

What am I missing?

Epaga
  • 38,231
  • 58
  • 157
  • 245

2 Answers2

10

To see the changes with Simulators you have to quit the app, and reload it (or build & run).

Simulators have never been able to receive Remote Notifications to trigger an iCloud sync so you need to manually force a sync, but I've found that syncing cannot be triggered manually from the menu in my Xcode 11 beta (gives an error).

There is a good post by Andrew Bancroft about some other things such as setting the automaticallyMergesChangesFromParent property to true, but this doesn't make a difference when using Simulators (EDIT: It does, but I didn't realise as I was just building & running each time).

Andrew's Post: https://www.andrewcbancroft.com/blog/ios-development/data-persistence/getting-started-with-nspersistentcloudkitcontainer/#where-s-my-data

I'm in the same boat as I can't afford to install any beta software (except Xcode) so I'm going to have to stick with the simulators. But my experience of converting an existing App to CloudKit has been very, very positive. I just had to do three things to my existing project:

  • Add Background Notification & CloudKit capabilities
  • Make sure all Core Data attributes & relationships are optional (or have a default value if nil)
  • Rename NSPersistentContainer to NSPersistentCloudKitContainer

...and that's it! Mind blown.

All my nested many-to-many relationships appear to work perfectly.

I still need to work out how to sync images currently stored as JPGs in the users Documents directory but I suspect they'll need to be stored in Core Data as BLOBs to enable conversion to CKAssets in the background.

Paul Martin
  • 699
  • 4
  • 13
  • 1
    OK, when I set automaticallyMergesChangesFromParent to true, on the simulator I at least can get it to sync at app start (so simply build&run). Which is good enough for now. Great blog post, thanks. – Epaga Jun 15 '19 at 20:41
  • And when I run it on two separate iOS 13 devices, it syncs great! THIS IS AMAZING. – Epaga Jun 18 '19 at 11:15
  • Hi, have you tried it with old data? I'm trying to use it in my existing app but old data does not sync, only the new one that I've added after implementing NSPersistentCloudKitContainer – Wojtek Jun 18 '19 at 12:42
  • Have any of your tried building the Mac version of the sample app? It doesn't sync reliably for me using Apple's sample project: https://developer.apple.com/documentation/coredata/synchronizing_a_local_store_to_the_cloud – Clifton Labrum Jun 26 '19 at 19:19
  • @Wojtek Yes, it seemed to work with existing data in my app, with syncing occurring almost immediately (albeit slowly). There doesn't seem to be a way to prioritise entities or to see the progress of specific entities (particularly BLOBs syncing as CKAssets). I think I'll be waiting several months before implementing this in a real app but I'm VERY excited about it. – Paul Martin Jun 27 '19 at 21:29
  • Does this "quit reload" step is only needed on the receiving end for you guys? When I test with one simulator and monitoring the cloudkit dashboard, I noticed that adding an item also needs the simulator to be "quit reload" before it can be seen on the dashboard. – Phuah Yee Keat Sep 16 '19 at 03:38
  • As a followup: storing images as BLOBs in CoreData syncs perfectly. The only I'm still having is how slow it is to sync, and how little feedback you get to relay to users. As each relationship is a 'CKRecord' of sorts, the .limitExceeded error is constantly thrown with large databases so syncing an existing database takes AGES and there is no way to know when it will be finished - and then one day the data is suddenly in-sync. I can see my users thinking it's borked and deleting and re-importing their data - which will only make things worse!! :-/ – Paul Martin Oct 20 '19 at 02:23
  • @PaulMartin suffering same problem as @Wojtek - all testing using Simulator and on device, sync only works with "new" data added since changing from `NSPersistentContainer` to `NSPersistentCloudKitContainer`. I've read that for existing app data, I should load the existing data into the CloudKit container context and then save that... do you have any advice? – andrewbuilder Oct 20 '19 at 02:37
  • 1
    Also a note on using the Simulator and forcing a sync by quit and reload or Build & Run... I've found, all that is necessary (using Xcode 11.1) is to "press" the home button and then the app button, even if the app on that Simulator is not the current app run by Xcode. I assume that sending the app to the background and then bringing it to foreground is now enough to force a sync. – andrewbuilder Oct 20 '19 at 03:59
  • I've ended up resaving all old data so it syncs. – Wojtek Oct 20 '19 at 11:03
  • So I managed to get this all working, deployed my scheme to production and released my app. NOT ONE of my users are able to sync their data! Mine syncs just fine but not one of my users can sync. I can’t see what I missed. All I’m seeing are vague ‘’BAD_REQUEST” errors in the logs/telemetry on iCloud Dashboard, but they’re entirely unhelpful errors. – Paul Martin Oct 30 '19 at 18:41
  • Followup to the last comment... it seems like *one* entity's attribute didn't appear in the final development schema update so when I deployed to production, it was missing. But because my App on my test devices had *already been syncing* correctly, I never saw this error. I've fixed the missing schema attribute so time will tell if it now works for my users... – Paul Martin Nov 06 '19 at 08:32
  • 2
    @andrewbuilder I simply have a BOOL entity which I toggle on all my NSManagedObjects and then save the context. This will trigger a sync on old data. – Paul Martin Nov 06 '19 at 08:34
0

Apple now have example code called CoreDataCloudKitDemo. This includes all the basic stuff and also has additional code which processes the changes when they arrive from the other device. You need to have the lines

description.cloudKitContainerOptions = NSPersistentCloudKitContainerOptions( containerIdentifier: "iCloud.com.developerid.databasename")

to get your local database going to iCloud and creating the schema. You need to use the Cloudkit Dashboard on the web to see the schema etc.

SundialSoft
  • 136
  • 8