CloudKit: preventing duplicate records

I am working through an application that pulls data from an external web service into a private CloudKit database. The app is a single user app, however I am running into a race condition and I am not sure how to avoid it.

Each record in my external data has a unique identifier that I map to CKRecord instances. General application launch thread:

  • Get the current CKRecords for the corresponding record type.
  • Extracting external records.
  • For each external entry, if it does not exist in CloudKit, create it using batch create (modify operation).

Now the problem is that if this process runs simultaneously on two user devices, since the CK and the external fetch are asynchronous, there is a good chance that I will get duplicate records.

I know I can use zones to atomize all of my CKRecord instances, but I don't think that solves my problem, because if all these selections happen at the same time, persistence is not a problem.

My questions:

  • Does anyone know how to "lock" a personal database for writing across all user devices?
  • Alternatively, is there a way to enforce uniqueness on any CKRecord field?
  • Or is there a way to use the custom value as the primary key, in which case I could use my external id as the CK id and let the system prevent duplicates.

Thanks for the help in advance!

+3


source to share


2 answers


Answers:

  • No, you cannot lock a private database
  • Cloudkit already enforces and assumes that your Record ID is unique
  • You can make the post id whatever you like (in the neon part).

Explanation:



Regarding your duplication problem. If you are creating record ids (from external records that you mentioned, for example), then in the worst case you should have one record to record another with the same data if you have a race condition. I don't think this is a last resort problem. Two devices simultaneously start this process. Basically, the logic of first fetching existing records and then modifying them seems to be shown to me.

Code:

//employeeID is a unique ID to identify an employee
let employeeID = "001"

//Remember the recordID needs to be unique within the same database.
//Assuming you have different record types, it is better to prefix the record name with the record type so that it is unique
let recordName = "Employee-\(employeeID)"

//If you are using a custom zone
let customZoneID = CKRecordZoneID(zoneName: "SomeCustomZone", ownerName: CKCurrentUserDefaultName)
let recordIDInCustomZone = CKRecordID(recordName: recordName, zoneID: customZoneID)

//If you are using the default zone
let recordIDInDefaultZone = CKRecordID(recordName: recordName)

      

+4


source


I had a similar problem with duplicates loaded when I tried to read more than 100 records in the database; a solution is found in the Apple Atlas example, which uses a boolean to check if the last process exited before it starts the next one. You will find such a block ...

@synchronized (self)
    {
        // Quickly returns if another loadNextBatch is running or we have the oldest post
        if(self.isLoadingBatch || self.haveOldestPost) return;
        else self.isLoadingBatch = YES;
    }

      



By the way, here is the code to create your own record key.

CKRecordID *customID = [[CKRecordID alloc] initWithRecordName:    [globalEOConfirmed returnEOKey:i]];
    newrecord = [[CKRecord alloc] initWithRecordType:@"Blah" recordID:customID];

      

0


source







All Articles