2017-07-13 6 views
3

私は本当に奇妙な問題を抱えているので、CloudKitがどのように動作するのか理解できないか、CloudKitにバグがありました。CKRecordを削除するのは本当に混乱しています

ので、問題は次のようになります。

アプリの初期状態:

私は5 "パッケージ" の記録を持っている、B、C、Dそれらを呼び出すことができます、E.

ユーザアクション

ユーザは「パッケージ」レコードEを削除し、後である時点で最新の「パッケージ」レコードをすべて取り込む更新ボタンを押します雲から

問題

ユーザーが更新ボタンを押すと、アプリは基本的に既存のローカルに保存された「パッケージ」の記録を見ていきますと、他のレコードを取得する必要があり、述語とCKQueryを作成することローカルには存在しません。次のステップは基本的に[データベースperformQuery:inZoneWithID:completionHandler:]メソッドを呼び出すことです。

ユーザーが以前に削除した「パッケージ」レコードEを含む結果が表示されたら、驚きが表示されます。

このdoesntのは私には右のように見える...私はデバッグにかかった

手順:

  1. 右の「パッケージ」のレコードEを削除した後、私はCKFetchRecordsOperationを作成し、削除されたレコードを取得しようとしました。結果は期待どおりでした:私は "レコードが見つかりません"を得ました。私はここでクールです。

  2. サーバー側で遅れがあるかもしれないと思うので、私はdispatch_afterブロックを置き、ポイント1と同じフェッチ操作を開始しましたが、30秒後に開始しました。結果は期待どおりでした。「レコードが見つかりません」というエラーが出ました。

  3. ポイント2で行ったのと同じテストを100秒遅らせて実行しましたが、驚いたことに、CKFetchRecordsOperation操作によって、削除されたレコードEパッケージが返されました。奇妙なことは、それはまだそれはエラーを返すsomethingsですが、ときどき明らかに削除されたオブジェクトを返すだけです。

これは本当に奇妙な部分です:これはA、B、C、Dというレコードでは起こりません。すべてのレコードの間に1つの違いがあります。これは意味をなさない。

私は、バグレポートを満たし、私が得た回答は、このでした:これは正しい動作です

。クエリは最終的に一貫しているため、クエリの実行時に削除が即座に反映されないことがあります。 CKFetchRecordsOperationを介して削除されたレコードをIDで取得すると、すぐにCKErrorUnknownItemが返されます。

これは部分的には間違いありませんが、これは私が見ているものではないようです。

コード

  1. 名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]; 
      }]; 
      
    1. コードTHAのピースtは、ユーザーがいつでも押すことができるリフレッシュボタンを押すことによって、既存のすべてのレコードをフェッチします。私はこのコードを単純化して問題を公開しましたが、基本的に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を持つことができますが、今私はなぜこの問題があるのか​​理解しようとしています。

    p.s.私がCloudKitの最初の実装を私のアプリケーションに追加したとき、私はできるだけシンプルに同期させていました。 1年間はうまくいっていたので、ユーザーから、プロダクションの一部のレコードを削除できないという報告を受け始めました。

    これをさらにデバッグする方法についてのヒントはありますか?

    ありがとうございました!

  • +1

    [編集]問題を再現する関連コードで質問してください。 – rmaddy

    +2

    レコードの更新に要する時間は不明です。時間のかかるインデックス作成があります。ここに私が与えた答えがありますが、違いは削除についての言葉に注意を払いますが、レコードを追加することです。私はそれらを処理する方法は、削除されたレコードのキャッシュを維持することです。それらが結果にない場合、私はキャッシュをフラッシュします。基本的には、ユーザが期待するものと同じにするために結果をローカルにつなぐことを考えてください。 Link-https://stackoverflow.com/questions/42729601/how-to-update-data-in-tableview-without-the-delay-using-cloudkit-when-creating-n/42731220#42731220 – agibson007

    +1

    iCloudはありませんオラクル彼らの側で物事を想像してください。 iCloudサーバーのファームが必要です。すべてのサーバーは互いに同期していて、待ち時間がかなりあります。私は、https://stackoverflow.com/users/3641744/agibson007答えの原因は良い解決策を投票した。 CKFetchRecordsOperationが正しい結果を返すことがわかった場合は、ローカルにキャッシングしたくない場合には、そのようにしてください。 – user3069232

    答えて

    1

    私はレコードの種類を混在させ、名前(CKRecordIDの文字列)を記録していると思います。名前はCloudKit(通常)によって割り当てられ、タイプはあなたによって設定されます。私はそれが自動的に割り当てられたと思うだろうが、私は記録がどのように保存されたかを見なければならないだろう。 CloudKitダッシュボードのスクリーンショットを表示するように指示します。

    のコードブロックで、1)レコードタイプを使用して、一部のレコードのレコード名を削除しようとしています。そのため、「レコードが見つかりません」というエラーメッセージが表示されます。 2)まだレコードタイプを使用していて、レコード名を使用していないのと同じです。 3)実際に割り当てられたrecord.recordIDを使用しているため、レコードをフェッチします。

    これは私の状況です。私のanswerのレコードをステッチングして、UIとデータベースを同期した状態に保ってください。

    +1

    私はコードを二重にチェックしても、レコード名とタイプを混同するかどうかまだ分かりません。 Appleの文書によると、CKRecordIDは意味のある文字列を提供することで作成することができます。「各名前が指定されたゾーン内で一意である限り、アプリケーションやユーザーにとってより意味のある名前を自由に使用できます。これはまさに私がやっていることです。DS2000330803AS文字列をIDとして使用しています。なぜなら、これらの文字列は常に一意であることがわかっているからです。 – Andy

    +0

    あなたはスクリーンショットを気にしますか?それを見るためにダッシュボードからEを記録しますか?私はあなたを疑うことはありませんが、私は最高の推測と利用可能な情報を外していました。 Dashboardで作成された場合は、CloudKitによって割り当てられた一意の文字列と考えられます。 – agibson007

    +0

    ここにあります:https://www.dropbox.com/s/1xm3kv636w8m69l/Screenshot%202017-07-14%2017.25.57.png?dl=0奇妙なことは、私はダッシュボードからこのレコードを削除することができたことですそれはそれが "スタック"状態から抜け出しているように見え、アプリから削除することもできます(再作成した場合)、これはまったく新しいレコードなので、これは現在無関係です。これらは、フレームワークを実装する際に私をたくさん怖がらせるものです...私たちはすべて、クラウドの失敗でCore Dataを思い出します... – Andy

    関連する問題