2014-09-12 6 views
8

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

ответ

5

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

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

+0

Да, они были CKRecords и да, я использовал свежие CKRecords, чтобы перезаписать существующие, и да, ваше решение сработало! В документах не было очень явным. Ну что ж. Спасибо за ответ! – Jonathan

2

Вы должны разрешение на запись набора для соответствующих типов записей в dashboa я думаю.

enter image description here

+0

Не думал об этом. Просто дал ему выстрел, и это не сработало. – Jonathan

0

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

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

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

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

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

7

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

Однако, если удаленный CKRecord не существует вообще, запись сервера не изменилась и операция сохранения может продолжаться. Это поведение является основанием для использования сценария «Сохранить, если нет» (SQL: INSERT над PRIMARY KEY). Если вы назначили «local» CKRecord и используете savePolicy из CKRecordSaveIfServerRecordUnchanged, он будет INSERT, но никогда не ОБНОВЛЯЕТ.

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

Вариант использования «Сохранить, если существует» (SQL: ОБНОВЛЕНИЕ ПО ПЕРВИЧНОМУ КЛЮЧУ), вероятно, не может быть выполнен без (проверки) отключения по сети.

Улов: это не возможно, чтобы свернуть как в CKRecordSaveIfServerRecordUnchanged INSERT и UPDATE CKRecordSaveAllKeys в одну атомарную транзакцию, поскольку CloudKit транзакции охватывают только одного CKModifyRecordsOperation, для работы с несколькими CKRecord/CKRecordID экземпляров. Философски говоря, «транзакция» должна охватывать несколько «операций» (SQL: запросы), а не только несколько «записей» (SQL: rows).

Смежные вопросы