8

CloudKit でレコードの変更をアップロードしようとしています。CKModifyRecordsOperation を使用して、デバイス上で変更されたレコードのバッチ アップロードを行っています。レコードはすべてカスタム ゾーンにあります

何らかの理由で、「保護データが一致しませんでした」というエラーが表示されて操作が戻ってきます

コードは次のとおりです。

- (void)updloadLocalChangesWithCompletionBlock:(void (^)(NSError *error))completionBlock
{
   // Initialize the data
   NSArray *localChanges = self.localChanges;
   NSArray *localDeletions = self.localDeletions;

   // Initialize the database and modify records operation
   CKDatabase *database = [CKContainer defaultContainer].privateCloudDatabase;
   CKModifyRecordsOperation *modifyRecordsOperation = [[CKModifyRecordsOperation alloc] initWithRecordsToSave:localChanges recordIDsToDelete:localDeletions];
   modifyRecordsOperation.savePolicy = CKRecordSaveAllKeys;

   NSLog(@"CLOUDKIT Changes Uploading: %d", localChanges.count);

   // Add the completion block
   modifyRecordsOperation.modifyRecordsCompletionBlock = ^(NSArray *savedRecords, NSArray *deletedRecordIDs, NSError *error) {
       if (error) {
           NSLog(@"[%@] Error pushing local data: %@", self.class, error);
       }

       [self.localChanges removeObjectsInArray:savedRecords];
       [self.localDeletions removeObjectsInArray:deletedRecordIDs];

       completionBlock(error);
   };

   // Start the operation
   [database addOperation:modifyRecordsOperation];
}

これが私に与えているエラーです:

[CloudKitSyncManager] Error Uploading Changes: <CKError 0x156654a0: "Partial Failure" (2/1011); "Failed to modify some records"; partial errors: {
    default-00001:(ZoneName:UserRecordID) = <CKError 0x1550b5a0: "Server Record Changed" (14/2037); "Error saving record <CKRecordID: 0x18080430; default-00001:(ZoneName:UserRecordID)> to server: Protection data didn't match">
}>
4

4 に答える 4

7

の を使用する場合は、savePolicyCKRecordSaveIfServerRecordUnchanged前にリモートをプリフェッチCKRecord(およびその特定のインスタンスを更新) する必要がありますCKModifyRecordsOperation。「ローカル」を割り当てて、一致するでCKRecordそれをアップリファレンスすると、CloudKit はリモートの変更タグを (欠落している) ローカルの変更タグと比較できないため、次のややあいまいなエラー メッセージで失敗します。合わない」。CKRecordIDinitWithRecordName:CKErrorServerRecordChanged

ただし、リモートCKRecordがまったく存在しない場合は、確実にサーバー レコードが変更されておらず、保存操作を続行できます。この動作は、「存在しない場合は保存」ユース ケース (SQL: PRIMARY KEY に対する INSERT) の基礎です。「ローカル」を割り当ててofCKRecordを使用すると、INSERT は実行されますが、UPDATE は実行されません。savePolicyCKRecordSaveIfServerRecordUnchanged

If you use the savePolicy of CKRecordSaveAllKeys and the CKRecordZoneID ownerName of CKOwnerDefaultName, you should be able to save (SQL: UPDATE, with INSERT if necessary) through a "locally" allocated CKRecord, saving a (pre-fetch) trip over the network.

The "Save If Exists" use case (SQL: UPDATE over a PRIMARY KEY) probably cannot be done without a (verification) trip over the network.

A catch: it is not possible to roll both a CKRecordSaveIfServerRecordUnchanged INSERT and a CKRecordSaveAllKeys UPDATE into one atomic transaction, since CloudKit transactions span only a single CKModifyRecordsOperation, across multiple CKRecord/CKRecordID instances. Philosophically speaking, a "transaction" should be able to span multiple "operations" (SQL: queries), not just multiple "records" (SQL: rows).

于 2015-08-07T06:13:36.523 に答える
6

あなたのself.localChanges配列には正確に何がありますか?CKRecord私は推測しますが、アップロードしている変更されたレコードは、CloudKit からダウンロードした同じ CKRecord オブジェクトに基づいていますか?

新しく割り当てられた CKRecord をローカルの変更でアップロードしようとしたときに、同様の (正確ではありませんが) エラー メッセージが表示され、サーバーのコピーが上書きされることを期待していました。アイテムのリモート コピーをダウンロードし、CloudKit から提供された CKRecord インスタンスに更新を適用してから、アップロードすることで修正しました。

于 2014-10-04T00:45:07.330 に答える
2

ダッシュボードで対応するレコードの種類に書き込み権限を設定する必要があると思います。

ここに画像の説明を入力

于 2014-09-17T07:25:31.177 に答える
0

これに対する解決策が 2 つあったことは注目に値します。カスタムゾーンも使用しようとしていました。CKRecordZoneID を初期化していたところはどこでも、コードは次のようになりました。

[[CKRecordZoneID alloc] initWithZoneName:@"CustomZoneName" ownerName:self.userRecordId.recordName];

これは、このように見えるはずです

 [[CKRecordZoneID alloc] initWithZoneName:@"CustomZoneName" ownerName:CKOwnerDefaultName];

これが「保護データが一致しないバグ」の原因の一部であると思いますが、それを修正するには Dave Teare の回答も必要でした。

于 2014-10-09T04:59:01.090 に答える