删除CKRecord确实令人困惑

时间:2017-07-13 18:34:27

标签: ios xcode cloudkit ckrecord

所以我有一个非常奇怪的问题,我想我要么不明白CloudKit是如何工作的,要么我在CloudKit中遇到了一个错误。

所以,问题看起来像这样:

应用初始状态:

我有5个“套餐”记录,我们称之为A,B,C,D,E。

用户操作

用户将删除“Package”记录E,稍后他会按下刷新按钮,该按钮将从云中获取所有当前的“Package”记录。

问题

当用户按下刷新按钮时,应用程序将基本上查看现有的本地存储的“Package”记录,并将创建一个带有谓词的CKQuery,该谓词应该获取本地不存在的任何其他记录。下一步基本上是调用 [数据库performQuery:inZoneWithID:completionHandler:] 方法。

当我得到结果时会出现惊喜,其中包含用户先前删除的“包”记录E.

这似乎对我不对......

我调试的步骤:

  1. 在删除“Package”记录E后,我创建了一个CKFetchRecordsOperation并尝试获取已删除的记录。结果如预期:我得到了“未找到记录”。我很酷。

  2. 认为服务器端可能存在一些延迟,我放了一个dispatch_after块并启动了我在第1点但在30秒之后执行的相同提取操作。结果仍然如预期:我收到了“未找到记录”错误。

  3. 执行与第2点相同的测试,但延迟时间为100秒并且......惊喜,CKFetchRecordsOperation操作返回已删除的记录E包。奇怪的是,有些东西它仍然会返回一个错误,但有时会明确地返回已删除的对象。

  4. 现在非常奇怪的部分:记录A,B,C和D不会发生这种情况,所有这些记录之间的单一差异就是它们的名称。这没有任何意义。

    我填写了一份错误报告,我得到的答复是:

    这是正确的行为。查询最终是一致的,因此查询时可能无法立即反映删除。通过CKFetchRecordsOperation通过ID获取已删除的记录应立即返回CKErrorUnknownItem。

    虽然这部分属实,但我所看到的情况似乎并非如此。

    代码

    1. 删除名为DS2000330803AS的记录E,检查CKFetchRecordsOperation操作将返回错误,找不到记录。一切都很好。
    2. CKContainer *container = [CKContainer defaultContainer];
      CKDatabase *privateDB = [container privateCloudDatabase]; 
      
      CKRecordID *recordID = [[CKRecordID alloc] initWithRecordName: @"DS2000330803AS"];
      
      CKModifyRecordsOperation *operation = [[CKModifyRecordsOperation alloc] initWithRecordsToSave: nil recordIDsToDelete: @[recordID]];
      operation.database = privateDB;
      
      [operation setModifyRecordsCompletionBlock:^(NSArray<CKRecord *> * _Nullable savedRecords,
                                               NSArray<CKRecordID *> * _Nullable deletedRecordIDs,
                                               NSError * _Nullable error) {
      
          CKFetchRecordsOperation *fetchOperation = [[CKFetchRecordsOperation alloc] initWithRecordIDs:@[recordID]];
          fetchOperation.database = privateDB;
          [fetchOperation setPerRecordCompletionBlock:^(CKRecord * _Nullable record, CKRecordID * _Nullable recordID, NSError * _Nullable error){
              NSLog(@"Error: %@", error.localizedDescription);
          }];
      }];
      
      1. 在我的VC中放置NSTimer只是为了测试Record删除,这段代码将返回已删除的记录:
      2. [NSTimer scheduledTimerWithTimeInterval:100 repeats:NO block:^(NSTimer * _Nonnull timer) {
        
            CKContainer *container = [CKContainer defaultContainer];
            CKDatabase *privateDB = [container privateCloudDatabase];
        
            CKRecordID *recordID = [[CKRecordID alloc] initWithRecordName:@"DS2000330803AS"];
        
            CKFetchRecordsOperation *fetchOperation = [[CKFetchRecordsOperation alloc] initWithRecordIDs: @[recordID]];
            fetchOperation.database = privateDB;
            [fetchOperation setPerRecordCompletionBlock:^(CKRecord * _Nullable record, CKRecordID * _Nullable recordID, NSError * _Nullable error){
                NSLog(@"Error: %@", error.localizedDescription);
            }];
        
            [privateDB addOperation: fetchOperation];
        }];
        
        1. 通过按下用户可以随时按下的刷新按钮来获取所有现有记录的代码段。我简化了这段代码只是为了揭露问题,基本上performQuery返回DS2000330803AS记录,为了测试我的理智,我正在添加一个CKFetchRecordsOperation来再次获取记录,这当然确实返回它没有任何问题
        2. CKContainer *container = [CKContainer defaultContainer];
          CKDatabase *privateDB = [container privateCloudDatabase];
          
          NSPredicate *predicate = [NSPredicate predicateWithValue: YES];
          CKQuery *query = [[CKQuery alloc] initWithRecordType:@"Package" predicate:predicate];
          
          [privateDB performQuery:query
               inZoneWithID:nil       completionHandler:^(NSArray<CKRecord *> * _Nullable results, NSError * _Nullable error) {
          
              [results enumerateObjectsUsingBlock:^(CKRecord * _Nonnull record, NSUInteger idx, BOOL * _Nonnull stop) {
          
                  NSLog(@"Record ID: %@", record.recordID);
          
                  CKFetchRecordsOperation *fetchOperation = [[CKFetchRecordsOperation alloc] initWithRecordIDs: @[record.recordID]];
                  fetchOperation.database = privateDB;
                  [fetchOperation setPerRecordCompletionBlock:^(CKRecord * _Nullable record, CKRecordID * _Nullable recordID, NSError * _Nullable error){
                      NSLog(@"Error: %@", error.localizedDescription);
                  }];
          
                  [privateDB addOperation: fetchOperation];
              }];   
          }];
          

          其他说明:我删除并评论了与CloudKit相关的所有内容,上述代码是唯一与CloudKit交互的代码。我目前正在测试一台设备。

          我知道CKQuery可以有更好的NSPredicate,但现在我试着理解为什么我有这个问题。

          P.S。当我将CloudKit的第一个实现添加到我的应用程序时,我试图尽可能简单地保持它,没有任何花哨的同步东西。它运作良好一年,然后我开始从我的用户那里得到他们无法删除生产中的某些记录的报告。

          有关如何进一步调试此问题的任何提示?

          谢谢!

1 个答案:

答案 0 :(得分:1)

我认为你正在混合记录类型和记录名称(CKRecordID的字符串)。名称由CloudKit(通常)分配,类型由您设置。我敢打赌它是自动分配但我必须看看如何保存记录。它会告诉你看看你的CloudKit仪表板的截图。

在你的代码块中 1)您正在尝试使用记录类型删除某些记录的记录名称。这就是为什么你得到错误“找不到记录” 2)与您仍在使用记录类型而非记录名称相同 3)获取记录,因为它实际上使用了指定的record.recordID。

这是我对局势的直觉。至于删除和刷新,请在拼接记录中查看我的answer以保持UI和数据库同步。