Manually define a CKRecord ID for a given NSManagedObject instance

I have an app that is already running with CoreData, and I want to allow the users to upload their data to iCloud so, in the case they need to delete their apps or change devices, they don't lose it.

Every time the app is opened, there is a synchronization that happens between CoreData and a JSON file fixture, in order to fill the app with its base values (creating NSManagedObject instances from the aforementioned fixture).

Before the iCloud sync, the CoreData model had some constraints for different entities, to enforce uniqueness, but these had to be stripped since CloudKit doesn't support them. Most of these constraints were basically ids that came from the JSON and represent an item in our Firebase database.

Given that, I want to make the underlying CKRecord.id the same as these ids, so I can avoid the situation where, if a person open the app in a second device, the fixture data is repeated, since the fixture runs before the sync with the iCloud happens.

Is that possible? Any help would be appreciated.

Answered by DelawareMathGuy in 680977022

hi,

since you are using NSPersistentCloudKitContainer, you might want to take a look at Apple's page on Linking Data Between Two Core Data Stores.

this provides a mechanism so that you can load up what i think you are calling "base values" in a local store, separate from the store that is mirrored to iCloud. this would solve the problem of loading base values on one machine, moving them into the cloud, and then trying to figure out on a second device how to prevent them from being reloaded from iCloud.

hope that helps, DMG

I’m trying build live stream app I need help app like live me or yubo

Can you email me

Are you doing the synchronization manually? You can add your own CKRecordID when you first create the CKRecord previously to save it to CK. Once the record lives in CK, you can't edit the ID (as far as I know).

Just remember that the ID must be unique between all the CKRecord in your CKRecordZone.

Accepted Answer

hi,

since you are using NSPersistentCloudKitContainer, you might want to take a look at Apple's page on Linking Data Between Two Core Data Stores.

this provides a mechanism so that you can load up what i think you are calling "base values" in a local store, separate from the store that is mirrored to iCloud. this would solve the problem of loading base values on one machine, moving them into the cloud, and then trying to figure out on a second device how to prevent them from being reloaded from iCloud.

hope that helps, DMG

Hi DMG, I spent the last days implementing this solution to give you a proper feedback. Thank you so much for the direction, I've been able to separate the stores by using fetched properties relating the cloud entities to the local entities, just like the link pointed. But there's something weird happening when I access the fetched properties from a background context.

In my Entity A (EA) I have a fetchedPropertyId of type String that refers to an id property on Entity B (EB). At the same EA I have the fetched property that has a predicate that points to EB and is the following:

id == $FETCH_SOURCE.fetchedPropertyId

The code to fetch the property in EA's class is:

@NSManaged public var fetchedPropertyId: String?

var fetchedProperty: EB? {
    let value = value(forKey: "fetchedProperty")
     
    let fetchedProperties = value as? [EB]
     
    return fetchedProperties?.first
  }

Accessing eaInstance.fetchedProperty from the viewContext returns the correct values (nil if there's no fetchedPropertyId, and the correct item of type EB if fetchedPropertyId is defined).

The weird thing is, whenever I access eaInstance.fetchedProperty in another context, the following error is thrown:

[<NSTemporaryObjectID_default 0x7fe723f48070> valueForUndefinedKey:]: this class is not key value coding-compliant for the key fetchedPropertyId.

This happens if I get the object by getting the objectID from the viewContext's managedObject instance and pass it to backgroundContext.object(with: objectID) and even if I fetch the given object again.

Do you have any idea why is this happening?

I'm observing the same issue. Execution of code is performed within backgroundContext.performAndWait{} Accessing the parentObject in the backgroundContext.performAndWait is not an issue here, but as soon as I access fetchedProperties?.first I observe the error stated by @vinicius_likeappro

Did you manage to solve this issue?

Manually define a CKRecord ID for a given NSManagedObject instance
 
 
Q