CKModifyRecordsOperation — одновременное создание записей, на которые ссылаются?

#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
    }
  

Проблема в том, что когда я перехожу к сохранению, ошибка, которую я получаю обратно, такова:

Недопустимый список записей: Цикл обнаружен в графике записей

Это говорит о том, что у меня есть запись, ссылающаяся на саму себя, но я просматриваю запись за записью и ничего не вижу. Недели ссылаются на курс и уроки, но не сами по себе и т.д. Итак, моя единственная теория заключается в том, что, поскольку я пытаюсь сохранить элементы, которые ссылаются на другие элементы, которые еще не были созданы, то, что я пытаюсь сделать, невозможно.

Является ли правильный протокол здесь на самом деле моим оригинальным подходом? Или я чего-то не хватает?
Оригинальный подход:

  1. Сохранить курс
  2. Сохранить неделю
  3. Сохранение уроков
  4. Обновляйте недели ссылками на уроки
  5. Обновите курс ссылками на недели

Код операции 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 с массовым сохранением заключается в том, что он добавляет уровень глупости, проверяя, что создание элементов по отдельности не выполняется 🙂