7

I've recently released an app that uses NSPersistentCloudKitContainer. In development my database is synchronizing across devices as expected, but in production my database is not synchronizing at all. Once I debugged the situation, I realized I had to publish the iCloud Schema to production. But even after doing that, my app is not synchronizing across devices in production.

Has anyone experienced this? Is there something else I need to do for NSPersistentCloudKitContainer to work in production?

Jake
  • 13,097
  • 9
  • 44
  • 73
  • I have the same issue and I’m in the middle of a Technical Support Request with an Apple Engineer - so far, crickets.... but they’re looking into it. I had all the correct capabilities set, I made sure it was all working on my developer build, deployed the schema, and released my app. I’m the only person that’s seeing syncing occur - even with the App Store Version. It seems as though ‘normal’ users can’t actually create the private database/zone/whatever. Worse still, it’s corrupted some users’ local Core Data entities resulting in App launch crashes where ‘object ID is nil’ or something :( – Paul Martin Nov 05 '19 at 20:48
  • I should expand on the above. If I delete my local Xcode built app, delete all the iCloud data for it, reboot my device and install the App Store version of my app from scratch on my devices, it syncs. It seems like it’s some sort of subscription issue that happens automatically when developing (and transfers to production) but fails for users who only run the app in the production environment. At the moment I’m putting out spot fires & fixing issues with my user... or at least trying to. I feel like it’s 99% there but these final hurdles are doing damage. – Paul Martin Nov 05 '19 at 20:53
  • ...and I have NO idea how to fix the Core Data ‘object ID is nil’ crashes that NSPersistentCloudKitContainer seemed to inject into my users’ CoreData objects. It’s a fatal error that I can’t catch or fix. – Paul Martin Nov 05 '19 at 20:58

2 Answers2

18

I think have worked out what’s going on as I was having the same problem, despite following all the steps in Apple’s Documentation for NSPersistentCloudKitContainer.

To make sure your Core Data entities are all created correctly in the Development Environment, before deploying to the Production Environment, they recommend running (once) the .shouldInitializeSchema on your NSPersistentCloudKitContainer.

Problem is, this hasn’t been valid for months (see more below...) so the other way to do it - and the way I did it - was to create all my data on-the-fly, saving to Core Data which created the schema in the Development Environment via NSPersistentCloudKitContainer. I then deployed it to Production when it was working perfectly on my devices.

While it was working perfectly well for my data, it wasn’t working for any of my users in the real world using my App Store version of the App. It was a real head-scratcher.

It turns out that there were a few missing Custom Fields in one or two Custom Types in the CloudKit Schema for my Core Data model - attributes which exist in my model but which I no longer use (one was just an empty string which I never use).

Problem is, NSPersistentCloudKitContainer doesn’t like this, even if an NSManagedObject has attributes you don’t use, they must be present in the CloudKit Schema for it to work. It seems to need a Custom Field to match each attribute in the Core Data model exactly.

Why it worked on my devices might be related to the fact that at some point in the past, these Custom Types and Custom Fields were all present in the Development Environment prior to a reset, by which stage my devices had everything in place already for them in iCloud.

The Custom Types (as seen in your CloudKit Dashboard) need to have Custom Fields that match every Core Data Attribute for the corresponding Entity as well as a Custom Field for each ‘to-one’ relationship (I had one of those missing too). They are all the fields that start with CD_ which are autogenerated by NSPersistentCloudKitContainer.

The ‘to-many’ relationships seemed to be stored elsewhere.

With Apple’s help, they suggested running the .shouldInitializeSchema replacement initializeCloudKitSchema(options:) (not yet in their documentation!) on the container (just once) to fill in all the gaps.

When I did this, I noticed it didn’t actually add any missing Custom Fields at all, and when I ‘Deployed to Production’ there were no changes to make and while it still worked on my devices, production devices weren’t working. On further analysis, the missing fields were NOT added...

So, instead, I made sure some data was written to my test device for all these missing attributes & ‘to-one’ relationships, then tried again.

I could see they were all now present in the Development Schema, which I deployed to production. All the missing Custom Types and Custom Fields were listed in the change.

It now all works for my users!

What a complicated process. Partly my fault, partly Apple’s.

Paul Martin
  • 699
  • 4
  • 13
1

I had the same problem, in my case the problem was that I was only activating the capabilities in the "Debug" section, because it is the tab opened by default when selecting "Signing & Capabilities"

Double check that you are also activating the needed capabilities in the "Release" section.

enter image description here

David Cordero
  • 770
  • 6
  • 16
  • I have the same issue and this wasn’t the solution, sorry. I had all the correct capabilities set, I made sure it was all working on my developer build, deployed the schema, and released my app. I’m the only person that’s seeing syncing occur - even with the App Store Version. It seems as though ‘normal’ users can’t actually create the private database/zone/whatever – Paul Martin Nov 05 '19 at 20:47