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
и CKRecordZoneID
ownerName
из 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];
Я полагаю, что это является частью того, что вызывало ошибку "Защита данных не соответствовала", но ответ Дейва Тира также был необходим для ее устранения.