我正在开发一个应用程序,它将数据从外部Web服务提取到私有CloudKit数据库。该应用程序是一个单一的用户应用程序,但我遇到了竞争条件,我不知道如何避免。
我的外部数据中的每条记录都有一个唯一的标识符,我映射到我的CKRecord实例。一般的app启动流程是:
现在,问题是,如果此过程同时在两个用户设备上启动,因为CK和外部提取都是异步的,很有可能我会重复记录。
我知道我可以使用区域以原子方式提交我所有的CKRecord实例,但我认为这不能解决我的问题,因为如果所有这些提取同时发生,那么保存不是问题。
我的问题是:
提前感谢您的帮助!
答案 0 :(得分:4)
关于您的重复问题。如果您是创建记录ID的人(例如,您提到的外部记录),那么在最坏的情况下,如果您有竞争条件,则应该有一个记录,而不是使用相同的数据写另一个记录。对于极端情况,我不认为这是一个问题。两个设备同时启动此过程。基本上你首先获取现有记录然后修改它们的逻辑对我来说似乎是合理的。
//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)
答案 1 :(得分:0)
当我尝试读取超过100条记录的数据库时,我遇到了类似的重复副本问题;该解决方案可以在Apple的Atlas示例中找到,该示例使用布尔值来检查上一个进程在启动下一个进程之前是否已完成。你找到一个像这样的块......
@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;
}
顺便提一下,这里是创建自己的记录密钥的代码。
CKRecordID *customID = [[CKRecordID alloc] initWithRecordName: [globalEOConfirmed returnEOKey:i]];
newrecord = [[CKRecord alloc] initWithRecordType:@"Blah" recordID:customID];