Is a 3-way merge possible when resolving CloudKit conflicts?

I'm trying to handle the serverRecordChanged return code you get in CKError when you have a conflict and your using the savePolicy of ifServerRecordUnchanged.

According to the CKError.Code.serverRecordChanged documentation, I should be receiving all three records that I need to do a 3-way merge. The problem is that the ancestorRecord (CKRecordChangedErrorAncestorRecordKey can also be used to look it up in the userInfo) doesn't actually contain a record. It only contains the record metadata.

Is there something I need to be doing to get the full ancestorRecord in the CKError?

If not is it possible to query iCloud for the ancestorRecord? Given that iCloud has the change history (as I understand it), then it is theoretically possible. I just don't know how to do it if it is possible.

Are 3-way merges even possible? The design of the serverRecordChanged looks like that is the intent, but I can't see how to do it with the data that CloudKit is providing.

Hi there, I was wondering if you ever managed to sort this out. By the way, are your fields encrypted or unencrypted?

I have recently investigated this and from my observations, the ancestor record can include full field data, but only under specific conditions.

When you create the CKRecord to upload from system fields using CKRecord.encodeSystemFields(with:) and restore it with CKRecord.init(coder:), then fill in the fields manually, CloudKit will not populate the fields of the ancestor record in a serverRecordChanged error. You will only get the record metadata.

If instead you upload a CKRecord that was created from a full archive using CKRecord.encode(with:), or one that was fetched directly from CloudKit, the ancestor record in the conflict will contain all fields.

In short:

  • encodeSystemFields(with:) → ancestor has only metadata
  • encode(with:) or fetched record → ancestor has all fields
Is a 3-way merge possible when resolving CloudKit conflicts?
 
 
Q