ioscore-datacloudkitnsmanagedobjectckrecord

How do you get the CoreData NSManagedObject from a CloudKit CKRecord?


I am using CoreData for local storage and CloudKit to handle cloud sync. I have set up CloudKit subscriptions to detect remote changes. These notifications provide a CKRecord representing the data which was added. The records are automatically synced with the CoreData store. How can I reconcile the CKRecord to an NSManagedObject? I need to be able to interact with it in the same way I do the entities fetched directly from CoreData.

Here is something I have been working on code-wise. The problem is that the recordName field which identifies the record in CloudKit does not exist in the CoreData store, so I get an unhandled exception. But I don't know what field (if any) will match the CloudKit record's name field.

//CKRecord+NSManagedObject

- (NSManagedObject*)managedObject {
    NSPersistentCloudKitContainer *container = [CoreDataFunctions persistentContainer];
    NSManagedObjectModel *managedObjectModel = container.managedObjectModel;
    NSDictionary *entitiesByName = managedObjectModel.entitiesByName;
    NSString *recordType = [self.recordType stringByReplacingOccurrencesOfString:@"CD_" withString:@""];

    NSEntityDescription *entityDescription = [entitiesByName valueForKey:recordType];
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:entityDescription.name];
    fetchRequest.fetchLimit = 1;
    fetchRequest.predicate = [NSPredicate predicateWithFormat:@"recordName == %@", self.recordID.recordName];
    NSError *error = nil;
    NSArray *results = [[CoreDataFunctions managedObjectContext] executeFetchRequest:fetchRequest error:&error];
    NSManagedObject *managedObject;
    if (error) {
        NSLog(@"Error %@", error);
    }
    else {
        if (results.count == 0) {
            NSLog(@"No result");
        }
        else {
            managedObject = results.firstObject;
            NSLog(@"%@", managedObject.entity.propertiesByName);
        }
    }

    return managedObject;
}

Solution

  • I don't know if there is a better way, but I ended up adding a field to my CoreData database called cloudID. Every time an NSManagedObject instance is created and inserted into the database, its cloudID is set to [NSUUID UUID]. This gets pushed up to the same field in CloudKit, so I can then use it to match the CloudKit CKRecord with the CoreData NSManagedObject.