私は本当に奇妙な問題を抱えているので、CloudKitがどのように動作するのか理解できないか、CloudKitにバグがありました。CKRecordを削除するのは本当に混乱しています
ので、問題は次のようになります。
アプリの初期状態:
私は5 "パッケージ" の記録を持っている、B、C、Dそれらを呼び出すことができます、E.
ユーザアクション
ユーザは「パッケージ」レコードEを削除し、後である時点で最新の「パッケージ」レコードをすべて取り込む更新ボタンを押します雲から
問題
ユーザーが更新ボタンを押すと、アプリは基本的に既存のローカルに保存された「パッケージ」の記録を見ていきますと、他のレコードを取得する必要があり、述語とCKQueryを作成することローカルには存在しません。次のステップは基本的に[データベースperformQuery:inZoneWithID:completionHandler:]メソッドを呼び出すことです。
ユーザーが以前に削除した「パッケージ」レコードEを含む結果が表示されたら、驚きが表示されます。
このdoesntのは私には右のように見える...私はデバッグにかかった
手順:
右の「パッケージ」のレコードEを削除した後、私はCKFetchRecordsOperationを作成し、削除されたレコードを取得しようとしました。結果は期待どおりでした:私は "レコードが見つかりません"を得ました。私はここでクールです。
サーバー側で遅れがあるかもしれないと思うので、私はdispatch_afterブロックを置き、ポイント1と同じフェッチ操作を開始しましたが、30秒後に開始しました。結果は期待どおりでした。「レコードが見つかりません」というエラーが出ました。
ポイント2で行ったのと同じテストを100秒遅らせて実行しましたが、驚いたことに、CKFetchRecordsOperation操作によって、削除されたレコードEパッケージが返されました。奇妙なことは、それはまだそれはエラーを返すsomethingsですが、ときどき明らかに削除されたオブジェクトを返すだけです。
これは本当に奇妙な部分です:これはA、B、C、Dというレコードでは起こりません。すべてのレコードの間に1つの違いがあります。これは意味をなさない。
私は、バグレポートを満たし、私が得た回答は、このでした:これは正しい動作です
。クエリは最終的に一貫しているため、クエリの実行時に削除が即座に反映されないことがあります。 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); }]; }];
-
は、コードのこの部分は削除されたレコードを返します。
- コードTHAのピースtは、ユーザーがいつでも押すことができるリフレッシュボタンを押すことによって、既存のすべてのレコードをフェッチします。私はこのコードを単純化して問題を公開しましたが、基本的にperformQueryはDS2000330803ASレコードを返します。私の健全性をテストするために、私はCKFetchRecordsOperationを追加してレコードを再度取得します。 。
[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]; }];
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年間はうまくいっていたので、ユーザーから、プロダクションの一部のレコードを削除できないという報告を受け始めました。
これをさらにデバッグする方法についてのヒントはありますか?
ありがとうございました!
[編集]問題を再現する関連コードで質問してください。 – rmaddy
レコードの更新に要する時間は不明です。時間のかかるインデックス作成があります。ここに私が与えた答えがありますが、違いは削除についての言葉に注意を払いますが、レコードを追加することです。私はそれらを処理する方法は、削除されたレコードのキャッシュを維持することです。それらが結果にない場合、私はキャッシュをフラッシュします。基本的には、ユーザが期待するものと同じにするために結果をローカルにつなぐことを考えてください。 Link-https://stackoverflow.com/questions/42729601/how-to-update-data-in-tableview-without-the-delay-using-cloudkit-when-creating-n/42731220#42731220 – agibson007
iCloudはありませんオラクル彼らの側で物事を想像してください。 iCloudサーバーのファームが必要です。すべてのサーバーは互いに同期していて、待ち時間がかなりあります。私は、https://stackoverflow.com/users/3641744/agibson007答えの原因は良い解決策を投票した。 CKFetchRecordsOperationが正しい結果を返すことがわかった場合は、ローカルにキャッシングしたくない場合には、そのようにしてください。 – user3069232