gpt4 book ai didi

ios - 删除 CKRecord 真的很困惑

转载 作者:行者123 更新时间:2023-12-02 04:13:05 25 4
gpt4 key购买 nike

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

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

应用初始状态:

我有 5 条“包裹”记录,我们称它们为 A、B、C、D、E。

用户操作

用户将删除“包”记录 E,并在稍后的某个时间点按下刷新按钮,该按钮将从云中获取所有当前的“包”记录。

问题

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

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

这似乎不适合我...

我调试的步骤:

  • 在删除“Package”记录 E 之后,我创建了一个 CKFetchRecordsOperation 并尝试获取已删除的记录。结果正如预期的那样:我得到了“找不到记录”。我在这里很酷。
  • 考虑到服务器端可能存在一些延迟,我放置了一个 dispatch_after block 并启动了与第 1 点相同的提取操作,但仅在 30 秒后。结果仍然如预期:我收到“找不到记录”错误。
  • 执行了与我在第 2 点中所做的相同的测试,但延迟了 100 秒并且......令人惊讶的是,CKFetchRecordsOperation 操作返回了已删除的记录 E 包。奇怪的是,它仍然会返回错误,但有时会简单地返回已删除的对象。

  • 现在真正奇怪的部分是:这不会发生在记录 A、B、C 和 D 上,所有这些记录之间的唯一区别是它们的名称。这没有任何意义。

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

    这是正确的行为。查询最终是一致的,因此查询时可能不会立即反射(reflect)删除。通过 CKFetchRecordsOperation 按 ID 获取已删除记录应立即返回 CKErrorUnknownItem。

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

    代码
  • 删除名称为 DS2000330803AS 的记录 E,检查 CKFetchRecordsOperation 操作返回错误,找不到记录。这里一切都好。

  • 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);
    }];
    }];

  • 在我的VC中放置一个NSTimer只是为了测试记录删除,这段代码将返回删除的记录:

  • [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];
    }];

  • 通过按下用户可以随时按下的刷新按钮获取所有现有记录的一段代码。我稍微简化了这段代码以暴露问题,基本上 performQuery 返回 DS2000330803AS 记录,为了测试我的理智,我添加了一个 CKFetchRecordsOperation 来再次获取记录,这当然返回它没有任何问题.

  • 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,但现在我试着理解为什么我会遇到这个问题。

    附:当我将 CloudKit 的第一个实现添加到我的应用程序时,我试图让它尽可能简单,没有任何花哨的同步内容。它工作了一年,然后我开始从我的用户那里收到他们无法删除生产中的某些记录的报告。

    关于我应该如何进一步调试的任何提示?

    谢谢!

    最佳答案

    我认为您混淆了记录类型和记录名称(CKRecordID 的字符串)。名称由 CloudKit(通常)分配,类型由您设置。我敢打赌它是自动分配的,但我必须看看记录是如何保存的。看到您的 CloudKit 仪表板的屏幕截图会很有趣。

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

    这是我对这种情况的直觉。至于删除和刷新请看我的answer关于拼接记录以保持 UI 和数据库同步。

    关于ios - 删除 CKRecord 真的很困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45088549/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com