I'm still writing my CKFetchRecordZoneOperation code...and I'm thinking about this situation. My database has a rule:
Child record requires existence of a parent record. In CloudKit terms, there is a CKReference wiith CKActionDeleteSelf. In my local SQLite database, the child table has a foreign key constraint referencing the parent.
During a CKFetchRecordZoneOperation, if another device creates a series of parent-child records and the current device is picking up the new records and saving it to the local cache, the insert for the parent record needs to be processed before child records. I haven't gotten to extensive testing yet, but if CKFetchRecordZoneOperation makes no guarentee of the order and passes changed child records to the app before the parent record, this could break local database rules and inserts of child records will be rejected by the local database because the parent isn't loaded yet. So say the parent record: Drinks has three children Juice, Milk, and Water. If CKFetchRecordZoneOperation hands back Juice, Milk, and Water before Drinks insertsof the child records will fail on the local database.
As the original poster mentioned, this could be addressed by the client code by sorting changes by record type:
[changeOp setRecordChangedBlock:^(CKRecord * _Nonnull record)
{
[changedRecords addObject:record];
}];
Then later when applying changes sort the array:
NSArray <ckrecord*>*sortedChangedRecs = [changedRecords sortedArrayUsingComparator:^NSComparisonResult(CKRecord *obj1,
CKRecord *obj2)
{
//Process
if ([obj1.recordType isEqualToString:@"GroupRecord"])
{
return NSOrderedAscending;
}
else
{
return NSOrderedDescending;
}
}];
But still may leave room for issues if CloudKit sends a client some children but doesn't send the parent over in the same batch, then sorting by record type will fail, because they aren't in the same batch. I can't assume CloudKit makes any guarantees that this stuff won't happen because I cannot find any documentation on this matter.
So it seems my choice is either:
-Allow the local database to insert child records where no parent exists (which is technically in violation of my app's rules, and could lead to orphaned entries in the database), but this would allow for children to be processed before parent records in a CKFetchRecordZoneOperation.
Or
-Attempt to insert into the local database with the child record blindly and if I get a constraint violation error, attempt to handle the error by querying CloudKit for the parent. This doesn't seem ideal because the client could be a few change tokens behind and querying the current database mid CKFetchRecordZoneOperation seems to undermine the purpose of CKFetchRecordZoneOperation (have the server tell you what changed based on the token instead of hard querying the database all the time)...
---
Unless Cloudkit is sophisticated enough to pass these changes back in logical order and I'm just being paranoid?