简体   繁体   中英

Fatal error: Dictionary<String, Any> does not conform to Decodable because Any does not conform to Decodable

I'm trying to use swift 4 to parse a local json file:

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

This is the function I'm using:

    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")}
        }
    }
}

but I keep getting the error:

Fatal error: Dictionary does not conform to Decodable because Any does not conform to Decodable.

I tried using the "AnyDecodable" approach on this stackoverflow page: How to decode a property with type of JSON dictionary in Swift 4 decodable protocol but it jumps to the 'catch' statement: catch { print("Local JSON not loaded") when being used. Does anyone know how to parse this JSON data in Swift 4?

Maybe you are misunderstanding how Codable works. It's based on concrete types. Any is not supported.

In your case you might create a struct like

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

And decode the 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)
}

Any crash will reveal a design error. The sense of using null in a file in the main bundle is another question.

I used quicktype to generate Codables and marshaling code:

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

I gave it an array of samples based on your sample data:

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

This tells quicktype to assume that the null values in your first sample are sometimes Int and String – you can change these if they aren't the possible types. The resulting Codable generated is:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM