将记录CKRecordID保存到服务器时出错:无效尝试更新类型' X'到了' Y'

时间:2016-05-17 13:44:22

标签: ios objective-c cloudkit ckmodifyrecordsoperation ckerror

虽然我使用CKModifyRecordsOperation将多个表的记录保存到私有云数据库的默认区域,但它始终会返回以下错误,除了表格&#39; X&#39;:< / p>

  

将记录保存到服务器时出错:尝试更新记录类型&#39; X&#39;到了&#39; Y&#39;

error.userInfo详细信息:

  

{
      CKErrorDescription =&#34;保存记录错误CKRecordID:0x7fd7a3d4c0c0; 1:(_ defaultZone: defaultOwner )到服务器:无效尝试更新类型&#39; X&#39;到&#39; Y&#39;&#34;;       ContainerID =&#34; iCloud.com ...&#34;;
      NSDebugDescription =&#34; CKInternalErrorDomain:2006&#34 ;;
      NSLocalizedDescription =&#34;将记录保存到服务器时出错:无效尝试更新类型&#39; X&#39;到&#39; Y&#39;&#34;;       NSUnderlyingError =&#34; CKError 0x7fa0d250c4e0:\&#34;无效参数\&#34; (2006年);服务器消息= \&#34;无效尝试更新类型&#39; X&#39;到了&#39; \&#34 ;; uuid = E2E ...... D1E;容器ID = \&#34; iCloud.com ... \&#34;&#34 ;;
      RequestUUID =&#34; E2E ...... D1E&#34 ;;
      ServerErrorDescription =&#34;无效尝试更新类型&#39; X&#39;到&#39; Y&#39;&#34;;       errorKey = ck1rosofi;
  }

相关代码段:

- (void)sync
{
  ...
  NSMutableArray * operations;
  for (NSString *tableName in @[@"X", @"Y"]) {
    CKModifyRecordsOperation * operation = [self _modifyRecordsOperationWithTableName:tableName];
    if (operation) {
      if (operations) [operations addObject:operation];
      else operations = [NSMutableArray arrayWithObject:operation];
    }
  }

  if (operations) {
    [operationQueue addOperations:operations waitUntilFinished:NO];
  }
}

- (CKModifyRecordsOperation *)_modifyRecordsOperationWithTableName:(NSString *)tableName
{
  ...

  NSMutableArray * recordsToSave = [NSMutableArray array];
  for (KYModel <KYModel_iCloudProtocol> *instance in unsyncedInstances) {
    CKRecordID * objectID = [[CKRecordID alloc] initWithRecordName:@(instance.id).stringValue];
    CKRecord * cloudRecord = [[CKRecord alloc] initWithRecordType:tableName recordID:objectID];
    ... setup record detail
    [recordsToSave addObject:record];
  }

  CKModifyRecordsOperation * operation = [[CKModifyRecordsOperation alloc] initWithRecordsToSave:recordsToSave recordIDsToDelete:nil];
  operation.database = [[CKContainer defaultContainer] privateCloudDatabase];
  operation.savePolicy = CKRecordSaveAllKeys;
  operation.qualityOfService = NSQualityOfServiceUserInteractive;
  operation.atomic = NO;
  operation.perRecordProgressBlock = ...;
  operation.perRecordCompletionBlock = ^(CKRecord *record, NSError *error) {
    if (error) {
      // got error here
    }
    ...
  };
  operation.modifyRecordsCompletionBlock = ...;

  return operation;
}

1 个答案:

答案 0 :(得分:0)

搜索后&amp;调试一段时间后,我意识到那些失败的记录有相同的记录名称&#34; (它是CKRecordID的唯一名称,它喜欢每个记录的唯一ID),虽然它们属于不同的表格,但它们属于同一个区域。

解决方案一:

制作CKRecordID&#39;记录姓名&#34;所有表格中都是独一无二的

例如,为每个记录名称添加一个表名前缀:[table_name] _ [id]。

我上面的案例的问题是&#34;记录名称&#34;重复显示同一区域(默认区域)中不同表格的记录。

使用CKModifyRecordsOperation&#39; CKRecordSaveAllKeys保存政策,当表Y的保存记录(id:1)时,它会在Cloud找到另一条表X的记录(id:1),并尝试修改它,这会引发错误&#34;无效尝试更新类型&#39; X&#39;最后到了#&#39;&#34;

解决方案二:

为每个表创建自定义区域(注意:自定义区域仅适用于私有云数据库)。

例如,不使用默认区域,而是使用客户区&#34; X_Zone&#34;表X和&#34; Y_Zone&#34;对于表Y.然后我们可以继续使用@&#34; id&#34;作为CKRecordID&#39;记录名称&#34;。

这样,在将本地记录转换为CKRecord实例时,您还需要提供zoneID

CKRecordZoneID * zoneID = [[CKRecordZoneID alloc] initWithZoneName:@"Custom_Zone_Name_Here"
                                                         ownerName:CKOwnerDefaultName];
CKRecordID * objectID = [[CKRecordID alloc] initWithRecordName:@(instance.id).stringValue zoneID:zoneID];
...

当然,您需要先创建相关的自定义区域:

CKRecordZone * zone = [[CKRecordZone alloc] initWithZoneName:@"Custom_Zone_Name"];
[[[CKContainer defaultContainer] privateCloudDatabase] saveRecordZone:zone completionHandler:...];

或同时创建多个:

NSMutableArray * zones = [NSMutableArray array];
for (NSString *zoneName in @[...]) {
  CKRecordZone * zone = [[CKRecordZone alloc] initWithZoneName:zoneName];
  [zones addObject:zone];
}
CKModifyRecordZonesOperation * operation = [[CKModifyRecordZonesOperation alloc] initWithRecordZonesToSave:zones recordZoneIDsToDelete:nil];
...
[[[CKContainer defaultContainer] privateCloudDatabase] addOperation:operation];

我测试过&amp; amp;按预期工作。

建议:

如果您的记录存储在私有云数据库中,我认为解决方案二将是一个不错的选择,正如DOC所说:

  

...使用自定义区域来排列和封装私有数据库中的相关记录组。自定义区域也支持其他功能,例如将多个记录作为单个原子事务写入的能力。

     

将每个自定义区域视为与数据库中每个其他区域分开的单个数据单元。在区域内,您可以像在其他任何地方一样添加记录。   ...

处理每个表的记录会更方便,例如删除表的区域而不是查询&amp;删除同一区域中表格的记录。

但是注意,如果您在表中使用CKReference,请不要为这些表使用自定义区域,因为

  

... CKReference类不支持跨区域链接,因此每个引用对象必须指向与当前记录相同的区域中的记录。

顺便说一句,这是自我回答问题的答案,希望如果其他人得到同样的问题会有所帮助。如果我的回答有问题,请指出,并且也欢迎提出任何建议。:)