Swift Decodable JSON dictionary with heterogeneous array Swift Decodable JSON dictionary with heterogeneous array json json

Swift Decodable JSON dictionary with heterogeneous array


I'm fairly certain your case is similar to a question I recently posted: Flattening JSON when keys are known only at runtime.

If so, you could use the following solution:

struct MyJSONData: Decodable {    var dates = [Any]()    init(from decoder: Decoder) throws {        var container = try decoder.unkeyedContainer()        // Only use first item        let stringItem = try container.decode(String.self)        dates.append(stringItem)        let numberItem = try container.decode(Int.self)        dates.append(numberItem)    }}let decoded = try! JSONDecoder().decode([String : [MyJSONData]].self, from: jsonData).values// Returns an Array of MyJSONData

Working solution: http://swift.sandbox.bluemix.net/#/repl/59949d74677f2b7ec84046c8


I was working with an API which encoded JSON array with heterogeneous data like yours, but even the order of the columns was not know before hand :(

In general, I strongly recommend against storing data in heterogeneous arrays. You will very quickly forget what index stands for what property, not to mention the constant cast back and forth. Instead, make a data model to store it when you decode from the array.

Another thing to note is that your date isn't what JSONDecoder expects by default. It expects ISO 8601 format (yyyy-MM-ddTHH:mm:ssZ) whereas the time component is missing from your date string. You can tell JSONDecoder what to do by supplying a custom DateFormatter:

struct WordData: Decodable {    var date: Date    var anInt: Int    init(from decoder: Decoder) throws {        var container = try decoder.unkeyedContainer()        self.date = try container.decode(Date.self)        self.anInt = try container.decode(Int.self)    }}var dateFormatter = DateFormatter()dateFormatter.locale = Locale(identifier: "en_us_POSIX")dateFormatter.timeZone = TimeZone(identifier: "UTC")dateFormatter.dateFormat = "yyyy-MM-dd"let decoder = JSONDecoder()decoder.dateDecodingStrategy = .formatted(dateFormatter)let words = try decoder.decode([String: [WordData]].self, from: jsonData)