Кодировщик и декодер пользовательского словаря для протокола Codable в Swift 4

Если у меня есть структура, соответствующая протоколу Codable, например:

enum AnimalType: String, Codable {
    case dog
    case cat
    case bird
    case hamster
}

struct Pet: Codable {
    var name: String
    var animalType: AnimalType
    var age: Int
    var ownerName: String
    var pastOwnerName: String?
}

Как я могу создать кодировщик и декодер, который кодирует/декодирует его в/из экземпляра типа Dictionary<String, Any?> вот так?

let petDictionary: [String : Any?] = [
    "name": "Fido",
    "animalType": "dog",
    "age": 5,
    "ownerName": "Bob",
    "pastOwnerName": nil
]
let decoder = DictionaryDecoder()
let pet = try! decoder.decode(Pet.self, for: petDictionary)

Примечание: я знаю, что можно использовать классы JSONEncoder и JSONDecoder перед преобразованием результата в объект словаря, но я не хочу этого из соображений эффективности.

Стандартная библиотека Swift поставляется с классами JSONEncoder и JSONDecoder, а также с классами PListEncoder и PListDecoder прямо из коробки, которые соответствуют протоколам Encoder и Decoder соответственно.

Моя проблема в том, что я понятия не имею, как реализовать эти протоколы для моих пользовательских классов кодировщика и декодера:

class DictionaryEncoder: Encoder {

    var codingPath: [CodingKey]

    var userInfo: [CodingUserInfoKey : Any]

    func container<Key>(keyedBy type: Key.Type) -> KeyedEncodingContainer<Key> where Key : CodingKey {

    }

    func unkeyedContainer() -> UnkeyedEncodingContainer {

    }

    func singleValueContainer() -> SingleValueEncodingContainer {

    }
}
class DictionaryDecoder: Decoder {

    var codingPath: [CodingKey]

    var userInfo: [CodingUserInfoKey : Any]

    func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> where Key : CodingKey {

    }

    func unkeyedContainer() throws -> UnkeyedDecodingContainer {

    }

    func singleValueContainer() throws -> SingleValueDecodingContainer {

    }
}

Учитывая, что Swift имеет открытый исходный код, можно просмотреть исходный код JSONEncoder и PListEncoder в стандартной библиотеке, но исходные файлы огромны и трудны для понимания из-за отсутствия документации, за исключением нескольких комментариев.


person Toni Sučić    schedule 19.10.2017    source источник
comment
Если вы не хотите использовать JSONDecoder, то зачем внедрять протоколы Codable?   -  person NSAdi    schedule 20.10.2017
comment
Протокол Codable является обобщенным/универсальным и может использоваться для представления внешних структур данных с собственными типами Swift. В стандартной библиотеке Swift есть протоколы Encoder и Decoder, которые вы можете реализовать для создания собственного пользовательского кодировщика и декодера для протокола Codable. Стандартная библиотека Swift поставляется с двумя такими парами кодировщик/декодер: github.com/apple/swift/blob/master/stdlib/public/SDK/Foundation/ github.com/apple/swift/blob/master/stdlib/public/SDK/Foundation/   -  person Toni Sučić    schedule 20.10.2017
comment
Моя проблема в том, что код слишком сложен, и, кроме комментариев в базе кода, нет документации, объясняющей, как вы можете реализовать свой собственный кодировщик и декодер, соответствующие протоколам Encoder и Decoder соответственно.   -  person Toni Sučić    schedule 20.10.2017


Ответы (1)


Если вы посмотрите на реализацию JSONDecoder (здесь), вы увидите, что это двухэтапный процесс: 1. используйте JSONSerialization для преобразования Data в словарь json, затем 2. создайте экземпляр внутреннего класса _JSONDecoder для работы со словарем -> Codable преобразование объекта.

Существует некоторое обсуждение Форумы Swift о возможном раскрытии внутренних типов, и команда Swift может что-то предпринять по этому поводу в будущем. Кто-то также предложил стороннюю структуру для выполнения того, что вы хотите.

person Steven Grosmark    schedule 24.01.2018