CloudKit - How to use Configurations to properly segregate public and private data

I am trying to understand the concepts between two of the CloudKit code samples:

  • CoreDataCloudKitDemo, which shows sync between CoreData and CloudKit
  • CoreDataFetchedProperty which shows how you can keep public and private data in two CoreData configurations and join them together.

After some trial and error I created a single NSPersistentCloudKitContainer that I thought used the two separate configurations - each had it's own local persistent store, database scope was set properly for both stores, etc. But when I run the app it complained of the following:

Failed to load persistent stores:Error Domain=NSCocoaErrorDomain Code=134060 "A Core Data error occurred." UserInfo={NSLocalizedFailureReason=CloudKit integration does not allow relationships to objects that aren't sync'd. The following relationships have destination entities that not in the specified configuration.

EntityA: entityB - EntityB

So, I went back to the model and although I had created two separate Configurations (with EntityA in one and EntityB in the other, I had not enabled them for use in CloudKit. When I did that, then the app now refuses to build.

This feels like a common scenario so I am assuming I have misconfigured something in the model. Are there any pointers that can help me correct this?

Thanks

`

Answered by DelawareMathGuy in 733598022

hi Chris,

i did this separation of local and cloud configurations some time ago, and as i recall, the 2 problems that needs fixin' are:

  • you cannot have a Core Data relationship between objects in the different configurations, so you have to implement any such relationship yourself; and
  • you must designate that your cloud-based configuration attaches itself to the cloudkit container (while the local configuration does not).

the second requires a setting in the Core Data .xcdatamedeld file: tap on a configuration and check "Used with CloudKit in the Data Model Inspector.

the first is very cleverly, if not secretly, handled in CoreDataFetchedProperty in that there is a FetchRequest defined that makes it easy for objects in the local configuration to find associated objects in the cloud configuration by a UUID look-up (or it may be vice-versa, i can't remember right now).

that is, instead of a one-to-one relationship from A (local) to B (cloud) being defined in the Core Data model, assume that all A and B objects have been assigned UUIDs and that each object has an attribute maybe called associate containing the other object's UUID.

given an A, you find the associated B by doing a fetchRequest on all Bs to find the one that matches the UUID you saved in A.associate. you do the same to find any A associated with a given B.

you can do either of these directly in code, maybe by adding a computing property as an extension to each; but in CoreDataFetchedProperty they pre-define such a Fetch directly in the Core Data model that can be called directly using an aggregate/computed property with a @fetch syntax. i'm sorry i can't recall the exact syntax, but examine the pre-define Fetch and the properties of the objects carefully to find the syntax for this.

hope this helps,

DMG

I feel like the answer here is proper understanding of the Fetched Properties used in the CoreDataFetchedProperty example, but it's not completely clear in the example.

Accepted Answer

hi Chris,

i did this separation of local and cloud configurations some time ago, and as i recall, the 2 problems that needs fixin' are:

  • you cannot have a Core Data relationship between objects in the different configurations, so you have to implement any such relationship yourself; and
  • you must designate that your cloud-based configuration attaches itself to the cloudkit container (while the local configuration does not).

the second requires a setting in the Core Data .xcdatamedeld file: tap on a configuration and check "Used with CloudKit in the Data Model Inspector.

the first is very cleverly, if not secretly, handled in CoreDataFetchedProperty in that there is a FetchRequest defined that makes it easy for objects in the local configuration to find associated objects in the cloud configuration by a UUID look-up (or it may be vice-versa, i can't remember right now).

that is, instead of a one-to-one relationship from A (local) to B (cloud) being defined in the Core Data model, assume that all A and B objects have been assigned UUIDs and that each object has an attribute maybe called associate containing the other object's UUID.

given an A, you find the associated B by doing a fetchRequest on all Bs to find the one that matches the UUID you saved in A.associate. you do the same to find any A associated with a given B.

you can do either of these directly in code, maybe by adding a computing property as an extension to each; but in CoreDataFetchedProperty they pre-define such a Fetch directly in the Core Data model that can be called directly using an aggregate/computed property with a @fetch syntax. i'm sorry i can't recall the exact syntax, but examine the pre-define Fetch and the properties of the objects carefully to find the syntax for this.

hope this helps,

DMG

CloudKit - How to use Configurations to properly segregate public and private data
 
 
Q