Словарь String: Any не соответствует протоколу «Декодируемый»

Я пытаюсь реализовать Decodable для анализа запроса json, но запрос json имеет словарь внутри объекта.

Вот мой код:

    struct myStruct : Decodable {
        let content: [String: Any]
}

        enum CodingKeys: String, CodingKey {
            case content = "content"
}

Но я получаю эту ошибку:

Тип «MyClass.myStruct» не соответствует протоколу «Decodable»

Как объявить переменную как словарь без этой ошибки?

Я буду очень признателен за вашу помощь


person user2924482    schedule 25.04.2018    source источник
comment
Словарь не будет декодируемым. Может быть, опубликовать JSON.   -  person picciano    schedule 25.04.2018
comment
Any не соответствует Decodable, поэтому Dictionary<String:Any> тоже не соответствует. Если вам действительно нужно хранить словарь с полностью динамическими ключами/значениями и, следовательно, вы не можете использовать конкретные типы, а не Any, вам нужно придерживаться использования JSONSerialization. Если вы знаете все ключи и ожидаемые типы их значений, сохраните значения как свойства вашего класса с конкретными типами.   -  person Dávid Pásztor    schedule 25.04.2018
comment
@ user2924482 Взгляните на мой ответ ниже. Лучшее из обоих: Decodable + [String:Any]   -  person staticVoidMan    schedule 25.04.2018


Ответы (2)


В настоящее время вы не можете декодировать [String: Any] с помощью среды кодирования Swift. Вам нужно будет перейти к стратегии десериализации более низкого уровня и декодировать «вручную», если вам нужно декодировать файл [String: Any]. Например, если вы вводите данные в формате JSON, вы можете использовать библиотеку Foundation JSONSerialization или стороннюю библиотеку, например SwiftyJSON.

Эта проблема обсуждалась на Swift Evolution: «Декодировать объект JSON неизвестного формата в словарь с декодируемым в Swift 4». Главный программист Apple Coding/Codable, Итай Фербер, участвовал в обсуждении и заинтересован в предоставлении решения, но это вряд ли произойдет для Swift 5 (о чем, вероятно, будет объявлено на WWDC 2018 и завершено примерно в сентябре/октябре 2018 г.).

Вы можете скопировать реализацию JSONDecoder. (это открытый исходный код) в свой проект и измените его, чтобы добавить возможность получения неоцененного [String: Any]. Itai обсуждает необходимые изменения в ветке, на которую я ссылался выше.

person rob mayoff    schedule 25.04.2018

Ну... технически вы могли бы сделать это, но вам потребуется использовать сторонний компонент SwiftyJSON для словарное представление.

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

В этом случае продолжайте:

import SwiftyJSON

struct MyStruct : Decodable {
    //... your other Decodable objects like
    var name: String

    //the [String:Any] object
    var content: JSON
}

Здесь JSON — это объект SwiftyJSON, который будет заменять ваш словарь. Infact это также будет заменять массив.


Рабочий пример:

let jsonData = """
{
  "name": "Swifty",
  "content": {
    "id": 1,
    "color": "blue",
    "status": true,
    "details": {
        "array" : [1,2,3],
        "color" : "red"
    }
  }
}
""".data(using: .utf8)!

do {
    let test = try JSONDecoder().decode(MyStruct.self,
                                        from: jsonData)
    print(test)
}
catch {
    print(error)
}
person staticVoidMan    schedule 25.04.2018