CloudKit CKModifyRecordsOperation дает мне "Защита данных не соответствует"

Я пытаюсь загрузить некоторые изменения записи с 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 ответа

Решение

Что именно в вашем self.localChanges массив? CKRecord Я предполагаю, но измененные записи, которые вы загружаете, основаны на тех же объектах CKRecord, которые вы загрузили из CloudKit?

У меня было похожее (хотя и не точное) сообщение об ошибке, когда я пытался загрузить недавно выделенный CKRecord с моими локальными изменениями и ожидал, что он перезапишет копию сервера. Я исправил это, загрузив удаленную копию моего элемента, применив обновления к экземпляру CKRecord, предоставленному мне CloudKit, и затем загрузив его.

Если вы используете savePolicy из CKRecordSaveIfServerRecordUnchangedнеобходимо предварительно извлечь пульт CKRecord (и обновить этот конкретный экземпляр) перед CKModifyRecordsOperation, Если вы выделите "местный" CKRecord и ссылаться на это через CKRecordID с соответствием initWithRecordName:CloudKit не может сравнить удаленный тег изменения с (отсутствующим) локальным тегом изменения, поэтому он не CKErrorServerRecordChanged и несколько расплывчатое сообщение об ошибке: "данные защиты не совпадают".

Тем не менее, если пульт CKRecord не существует вообще, конечно, запись сервера не изменилась, и операция сохранения может продолжаться. Это поведение является основой для варианта использования "Сохранить, если не существует" (SQL: INSERT over PRIMARY KEY). Если вы выделите "местный" CKRecord и использовать savePolicy из CKRecordSaveIfServerRecordUnchanged, он будет вставлять, но никогда не обновлять.

Если вы используете savePolicy из CKRecordSaveAllKeys и CKRecordZoneIDownerName из CKOwnerDefaultName, вы должны быть в состоянии сохранить (SQL: UPDATE, с INSERT, если необходимо) через локально выделенный CKRecord, сохраняя (предварительную) поездку по сети.

Вариант использования "Сохранить, если существует" (SQL: UPDATE поверх PRIMARY KEY), вероятно, невозможно выполнить без (проверки) отключения по сети.

Подвох: невозможно бросить оба CKRecordSaveIfServerRecordUnchanged ВСТАВИТЬ и CKRecordSaveAllKeys ОБНОВЛЕНИЕ в одну атомарную транзакцию, поскольку транзакции CloudKit охватывают только одну CKModifyRecordsOperationчерез несколько CKRecord/CKRecordID экземпляров. С точки зрения философии, "транзакция" должна иметь возможность охватывать несколько "операций" (SQL: запросы), а не только несколько "записей" (SQL: строки).

Я полагаю, вы должны установить разрешение на запись для соответствующих типов записей в панели управления.

введите описание изображения здесь

Стоит отметить, что решение этой проблемы было двояким. Я также пытался использовать пользовательскую зону. Где бы я ни инициализировал CKRecordZoneID, код выглядел так:

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

Это должно было выглядеть так

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

Я полагаю, что это является частью того, что вызывало ошибку "Защита данных не соответствовала", но ответ Дейва Тира также был необходим для ее устранения.

Другие вопросы по тегам