Как сохранить словарь (или любую другую сложную структуру) в iCloud с помощью Cloudkit?

#ios #swift #icloud #cloudkit #ckrecord

#iOS #swift #icloud #cloudkit #ckrecord

Вопрос:

Мне нужно привязать дату к значению и сохранить ее в Cloudkit. Вместо того, чтобы просто сохранять новый CKRecord для каждого объекта и подстрочного индекса «дата» и «значение», я бы предпочел, чтобы CKRecord это был массив dictionary: [(дата, значение)]. Я осмотрелся и не могу найти никаких примеров такого типа хранилища данных Cloudkit. Я бы уже подумал, что Codable был бы соединен с Cloudkit, но я не вижу ничего, указывающего на это. Существует библиотека, которая обрабатывает это, но она не обрабатывает этот тип вложенности. Есть ли какой-нибудь способ сделать это?

Ответ №1:

Хотя CKRecord есть возможность поддерживать Array , это в первую очередь для хранения простых типов данных, таких как строки, числа и CKRecord.Reference . Вы специально не указываете, какой у вас тип значения, но вот пример использования JSONEncoder / JSONDecoder для добавления поддержки записи / чтения любого кодируемого типа в CKRecord . Кодировщик / декодер просто преобразует Encodable / Decodable тип в / из двоичного Data представления, которое CKRecord также поддерживает.

 private let encoder: JSONEncoder = .init()
private let decoder: JSONDecoder = .init()

extension CKRecord {
    func decode<T>(forKey key: FieldKey) throws -> T where T: Decodable {
        guard let data = self[key] as? Data else {
            throw CocoaError(.coderValueNotFound)
        }
        
        return try decoder.decode(T.self, from: data)
    }
    
    func encode<T>(_ encodable: T, forKey key: FieldKey) throws where T: Encodable {
        self[key] = try encoder.encode(collection)
    }
}
  

Использование будет выглядеть следующим образом:

 let collection: [[Date: String]] = [[:]]
let record = CKRecord(recordType: "MyRecord")
try? record.encode(collection, forKey: "collection")
let persisted = try? record.decode(forKey: "collection") as [[Date: String]]