Неустранимая ошибка: Dictionary‹String, Any› не соответствует Decodable, потому что Any не соответствует Decodable

Я пытаюсь использовать swift 4 для анализа локального файла json:

{
    "success": true,
    "lastId": null,
    "hasMore": false,
    "foundEndpoint": "https://endpoint",
    "error": null
}

Это функция, которую я использую:

    func loadLocalJSON() {

        if let path = Bundle.main.path(forResource: "localJSON", ofType: "json") {
            let url = URL(fileURLWithPath: path)

            do {
                let data  = try Data(contentsOf: url)
                let colors = try JSONDecoder().decode([String: Any].self, from: data)
                print(colors)
            }
            catch { print("Local JSON not loaded")}
        }
    }
}

но я продолжаю получать ошибку:

Неустранимая ошибка: словарь не соответствует декодируемому, потому что любой не соответствует декодируемому.

Я попытался использовать подход «AnyDecodable» на этой странице stackoverflow: in-swift-4-decoded-proto">Как декодировать свойство с типом словаря JSON в декодируемом протоколе Swift 4, но оно переходит к оператору catch: catch { print("Local JSON not loaded") при использовании. Кто-нибудь знает, как анализировать эти данные JSON в Swift 4?


person SwiftyJD    schedule 27.02.2018    source источник


Ответы (2)


Возможно, вы неправильно понимаете, как работает Codable. Он основан на конкретных типах. Any не поддерживается.

В вашем случае вы можете создать структуру, например

struct Something: Decodable {
    let success : Bool
    let lastId : Int?
    let hasMore: Bool
    let foundEndpoint: URL
    let error: String?
}

И расшифровать JSON

func loadLocalJSON() {
    let url = Bundle.main.url(forResource: "localJSON", withExtension: "json")!
    let data  = try! Data(contentsOf: url)
    let colors = try! JSONDecoder().decode(Something.self, from: data)
    print(colors)
}

Любой сбой выявит ошибку проектирования. Смысл использования null в файле в основной связке - другой вопрос.

person vadian    schedule 27.02.2018
comment
Ах, это имеет смысл, это работает при такой настройке. Спасибо! - person SwiftyJD; 28.02.2018
comment
Обратите внимание, что вы можете использовать один try для обоих let colors = try! JSONDecoder().decode(Something.self, from: Data(contentsOf: url)) - person Leo Dabus; 28.02.2018

Я использовал quicktype для создания Codables и кода маршалинга:

https://app.quicktype.io?gist=02c8b82add3ced7bb419f01d3a94019f&l=swift

Я дал ему массив образцов на основе ваших выборочных данных:

[
  {
    "success": true,
    "lastId": null,
    "hasMore": false,
    "foundEndpoint": "https://endpoint",
    "error": null
  },
  {
    "success": true,
    "lastId": 123,
    "hasMore": false,
    "foundEndpoint": "https://endpoint",
    "error": "some error"
  }
]

Это говорит quicktype предположить, что значения null в вашем первом примере иногда бывают Int и String — вы можете изменить их, если они не являются возможными типами. В результате сгенерированный кодовый объект:

struct Local: Codable {
    let success: Bool
    let lastID: Int?
    let hasMore: Bool
    let foundEndpoint: String
    let error: String?

    enum CodingKeys: String, CodingKey {
        case success
        case lastID = "lastId"
        case hasMore, foundEndpoint, error
    }
}
person David Siegel    schedule 28.02.2018