CloudKit:防止重复记录

时间:2015-06-08 13:58:56

标签: ios objective-c icloud cloudkit

我正在开发一个应用程序,它将数据从外部Web服务提取到私有CloudKit数据库。该应用程序是一个单一的用户应用程序,但我遇到了竞争条件,我不知道如何避免。

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

  1. 获取相关记录类型的当前CKRecords。
  2. 获取外部记录。
  3. 对于每个外部记录,如果CloudKit中不存在,则通过批量创建(修改操作)创建它。
  4. 现在,问题是,如果此过程同时在两个用户设备上启动,因为CK和外部提取都是异步的,很有可能我会重复记录。

    我知道我可以使用区域以原子方式提交我所有的CKRecord实例,但我认为这不能解决我的问题,因为如果所有这些提取同时发生,那么保存不是问题。

    我的问题是:

    1. 有没有人知道如何锁定"用于在所有用户设备上进行写入的私有数据库?
    2. 或者,有没有办法在任何CKRecord字段上强制执行唯一性?
    3. 或者,有没有办法使用自定义值作为主键,在这种情况下,我可以使用我的外部ID作为CK ID,并允许系统本身防止重复。
    4. 提前感谢您的帮助!

2 个答案:

答案 0 :(得分:4)

的答案:

  1. 不,您无法锁定私人数据库
  2. Cloudkit已强制执行并假定您的记录ID唯一性
  3. 您可以随意制作记录ID(在非区域部分)。
  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];