CloudKit - How to Save Record If Not Exists

cloudkit, icloud, ios, ios8

Solution

If I understood correctly your use case, you can make movieRecord.recordID.recordName the movie's name and use `CKModifyRecordsOperation` with `savePolicy` `IfServerRecordUnchanged` to effectively Save If Not Exists. It would then return an error that you can ignore if you try to save a record that already exists on the server:

let saveRecordsOperation = CKModifyRecordsOperation()
saveRecordsOperation.recordsToSave = [movieRecord]
saveRecordsOperation.savePolicy = .IfServerRecordUnchanged

With the savePolicy `IfServerRecordUnchanged` this operation will save a new Movie record if it doesn't exist yet on the server (Save If Not Exists) but will return the error below on any subsequent try to overwrite a Movie record that already exists on the server (provided it is not a newer modified version of a record that was fetched from the server):

<CKError 0x14d23980: "Server Record Changed" (14/2017); server message = "record to insert already exists">

You could deal with this conflict in the `perRecordCompletionBlock` but in your specific use case you can just do nothing about the conflict error so each Movie record will be the first saved record with that CKRecordID.

Problem

I am trying to make a Record Type that contains unique values, and would act as the target reference objects to another Record Type. For example, Record Type - Movies would contain unique list of movies submitted by users. And FavoriteMovies would contain a Users reference and a Movies reference. Users could select from a list of existing Movies, or add new ones to it. The problem happens if I create a new Movies record, while another user creates a new record with the same name (after I retrieved the list of movies, but before I attempt to add a new one). The two new records are considered different records with different recordIDs. This means that once I saved the new one, there will be two instances of Movies with the save name. I'm not able to find a way to perform a Save If Not Exists type operation to the Movies Record Type. I could do a save in the completionBlock of a query, but those two actions would not be an atomic transaction to guarantee uniqueness. As far as I know this is also the case with chaining `CKQueryOperation` with `CKModifyRecordsOperation`. Is there a way to insert a record only if the value does not exists in a single transaction?

Original source