#swift #cloudkit
#swift #cloudkit
Вопрос:
Я работаю над рефакторингом несколько неуклюжего итеративного цикла сохранения для CloudKit, чтобы использовать CKModifyRecordsOperation и записи массового сохранения.
У меня есть Курс, который длится более 1 недели, в каждой из которых по 1 Уроку. Ранее я создавал курс в CloudKit, затем создавал недели, затем уроки и возвращался назад, чтобы обновить недели ссылками на уроки после создания. А также извлеките и сохраните запись курса со ссылками на Недели, как только Недели были созданы.
Я переработал, чтобы создать все записи (курса, недели и урока) локально, настроив соответствующие ссылки. Например, курс [«недели»] содержит ссылки на записи для каждой недели, которую я создал локально, например:
course["weeks"] = getWeekRefsForCourse(for: allWeeks)
func getWeekRefsForCourse(for allWeeks: [CKRecord]) -> [CKRecord.Reference] {
var weekRefsArray: [CKRecord.Reference] = []
for each in allWeeks {
let weekRef = CKRecord.Reference(record: each, action: .deleteSelf)
weekRefsArray.append(weekRef)
return weekRefsArray
}
Проблема в том, что когда я перехожу к сохранению, ошибка, которую я получаю обратно, такова:
Недопустимый список записей: Цикл обнаружен в графике записей
Это говорит о том, что у меня есть запись, ссылающаяся на саму себя, но я просматриваю запись за записью и ничего не вижу. Недели ссылаются на курс и уроки, но не сами по себе и т.д. Итак, моя единственная теория заключается в том, что, поскольку я пытаюсь сохранить элементы, которые ссылаются на другие элементы, которые еще не были созданы, то, что я пытаюсь сделать, невозможно.
Является ли правильный протокол здесь на самом деле моим оригинальным подходом? Или я чего-то не хватает?
Оригинальный подход:
- Сохранить курс
- Сохранить неделю
- Сохранение уроков
- Обновляйте недели ссылками на уроки
- Обновите курс ссылками на недели
Код операции CKModifyRecordsOperation:
let bulkSaveQueryOp = CKModifyRecordsOperation()
bulkSaveQueryOp.recordsToSave = [courseRecord]
bulkSaveQueryOp.recordsToSave?.append(contentsOf: weeks)
bulkSaveQueryOp.recordsToSave?.append(contentsOf: lessons)
//note I've confirmed I have the correct number of records
bulkSaveQueryOp.modifyRecordsCompletionBlock = { records, recordIDs, error in
if let error = error as? CKError {
log.error(error)
} else { // success }
}
CKContainer.default().publicCloudDatabase.add(bulkSaveQueryOp)
Ответ №1:
Я совершенно уверен, что вы можете создать все эти записи вместе. Я подозреваю, что должно быть что-то еще не так, и именно поэтому вы получаете эту ошибку.
Вы можете создать CKReference
объект , который даже не существует, и CloudKit все равно создаст его. A CKReference
— это немного больше, чем указатель на recordName
другой объект в контейнере.
Объединение всех этих записей в CKModifyRecordsOperation
является правильным решением, и вам не нужно быть осторожным с порядком ваших CKRecord
сохранений. Я думаю, что где-то должна скрываться другая проблема.
Комментарии:
1. Спасибо @Clifton — вы правы, вы можете создавать объекты, ссылающиеся друг на друга, и сохранять их одновременно. Оказывается, проблема заключалась в использовании действий .deleteSelf там, где это должно было быть .none!
Ответ №2:
Я смог найти аналогичный вопрос на форумах разработчиков Apple для кого-то, у кого была аналогичная проблема, и это помогло определить источник проблемы — что я фактически создал цикл с помощью своих действий .deleteSelf, которые я создавал для различных ссылок.
Итак, хотя ссылки были в порядке, именно действия были причиной ошибки.
Как только я дважды проверил и скорректировал их, ошибка исчезла, и я смог сохранить.
Обнаружение этого было усложнено тем фактом, что я не менял .Удалить версию действий с самим собой, что я ранее делал — и работал нормально — когда мои сохранения выполнялись последовательно, а не при массовом сохранении CKModifyRecordsOperation.
Таким образом, получается, что еще одно дополнительное преимущество CKModifyRecordsOperation с массовым сохранением заключается в том, что он добавляет уровень глупости, проверяя, что создание элементов по отдельности не выполняется 🙂