encodeSystemFields полезен, чтобы избежать повторного получения CKRecord из CloudKit для его обновления (исключение конфликтов записей).
Идея такая:
Когда вы сохраняете данные для записи, полученной из CloudKit (например, полученной через CKFetchRecordZoneChangesOperation для синхронизации изменений записей с локальным хранилищем):
1.) Заархивируйте CKRecord в NSData:
let record = ...
// archive CKRecord to NSData
let archivedData = NSMutableData()
let archiver = NSKeyedArchiver(forWritingWithMutableData: archivedData)
archiver.requiresSecureCoding = true
record.encodeSystemFieldsWithCoder(with: archiver)
archiver.finishEncoding()
2.) Храните архивные данные локально (например, в вашей базе данных), связанные с вашей локальной записью.
Если вы хотите сохранить изменения, внесенные в локальную запись, обратно в CloudKit:
1.) Разархивируйте CKRecord из сохраненных вами NSData:
let archivedData = ... // TODO: retrieved from your local store
// unarchive CKRecord from NSData
let unarchiver = NSKeyedUnarchiver(forReadingWithData: archivedData)
unarchiver.requiresSecureCoding = true
let record = CKRecord(coder: unarchiver)
2.) Используйте эту неархивированную запись как основу для ваших изменений. (т.е. установить на нем измененные значения)
record["City"] = "newCity"
3.) Сохраните записи в CloudKit с помощью CKModifyRecordsOperation.
Почему?
От Apple:
Хранение записей локально
Если вы храните записи в локальной базе данных, используйте метод encodeSystemFields (with :) для кодирования и хранения метаданных записи. Метаданные содержат идентификатор записи и тег изменения, которые понадобятся позже для синхронизации записей в локальной базе данных с записями, хранящимися в CloudKit.
Когда вы сохраняете изменения в CKRecord в CloudKit, вам необходимо сохранить изменения в записи сервера.
Вы не можете просто создать новый CKRecord с тем же идентификатором записи, установить для него значения и сохранить его. Если вы это сделаете, вы получите ошибку Server Record Changed - в данном случае это связано с тем, что существующая запись сервера содержит метаданные, которые отсутствуют в вашей локальной записи (созданной с нуля).
Итак, у вас есть два варианта решения этой проблемы:
Запросите CKRecord у CloudKit (используя идентификатор записи), внесите изменения в этот CKRecord, а затем сохраните его обратно в CloudKit.
Используйте encodeSystemFields и сохраните метаданные локально, разархивировав их, чтобы создать базовый CKRecord, содержащий все соответствующие метаданные для сохранения изменений в упомянутом CKRecord обратно в CloudKit.
# 2 спасает вас от сетевых циклов *.
* Предполагается, что другое устройство за это время не изменило запись - от чего также помогают защититься эти данные. Если другое устройство изменяет запись между моментом, когда вы в последний раз ее получили, и моментом, когда вы пытаетесь ее сохранить, CloudKit (по умолчанию) отклонит вашу попытку сохранения записи с измененной записью сервера. Это ваш ключ к разрешению конфликтов способом, который подходит для вашего приложения и модели данных. (Часто путем получения новой записи сервера из CloudKit и повторного применения соответствующих изменений значений к этой записи CKRecord перед повторной попыткой сохранения.)
ПРИМЕЧАНИЕ. Каждый раз, когда вы сохраняете / извлекаете обновленный CKRecord в / из CloudKit, вы должны не забывать обновлять локально сохраненный заархивированный CKRecord.
person
breakingobstacles
schedule
28.09.2016