2015-06-08 152 views
3

我正在通过将数据从外部Web服务提取到私有CloudKit数据库的应用程序工作。该应用程序是一个单用户应用程序,但我遇到了一个竞争条件,我不知道如何避免。CloudKit:防止重复记录

我的外部数据中的每条记录都有一个唯一的标识符映射到我的CKRecord实例。一般应用程序的启动流程如下:

  1. 获取相关记录类型的当前CKRecords。
  2. 获取外部记录。
  3. 对于每个外部记录,如果在CloudKit中不存在,则通过批量创建(修改操作)创建它。

现在,问题是,如果此过程在用户的两个设备上同时启动,因为CK和外部提取都是异步的,所以很有可能会得到重复记录。

我知道我可以使用区域自动提交所有的CKRecord实例,但我不认为这解决了我的问题,因为如果所有这些提取都发生在同一时间,则保存并不是真正的问题。

我的问题是:

  1. 有谁知道的方式在所有用户的设备的“锁定”为写入专用数据库?
  2. 另外,有没有办法强制CKRecord字段的唯一性?
  3. 或者,有没有办法使用自定义值作为主键,在这种情况下,我可以使用我的外部ID作为CK ID并允许系统防止重复本身。

感谢您的帮助!

+1

所以它看起来像我其实可以传递一个自定义名称到我自己的自定义CKRecordID,任何人都可以告诉我,如果这是正确的方式去做这件事? – nickbona

+1

是的,你可以添加自己的CKRecordID。然后它必须在整个容器中唯一(也可以在多个记录类型中) –

回答

4

答案:

  1. 不,你不能锁定专用数据库
  2. Cloudkit已经强制执行,并假设唯一的记录ID的
  3. 您可以记录ID任何你喜欢(在非区一部分)。

说明:

关于你的重复问题。如果您是创建记录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) 
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]; 
+0

当代码在同一用户的两个不同设备上同时运行时,这是不可能的。正确的解决方案是使用自定义的'CKRecordID'。根据唯一字段 – user1046037

+0

构建“CKRecordID”感谢您的反馈。你能用一个合适的解决方案的例子来分享一些代码吗? – user3069232

+0

那么使用一种创建'CKRecordID'的一致方式(就像你在答案中所显示的那样),所以当2个设备运行相同的代码来更新云记录时,它们将更新相同的记录而不是创建单独的记录。 '@ synchronized'不提供额外的安全性,因为它们可能是2个完全不同的设备,唯一的'CKRecordID'就足够了。 – user1046037