Extracting data from JSON array with swift Codable

懵懂的女人 提交于 2019-12-06 01:38:45

I cannot use [Any] here.

Never use Any when decoding JSON because usually you do know the type of the contents.

To decode an array you have to use an unkeyedContainer and decode the values in series

struct PortfolioResponseModel: Decodable {
    var dataset: Dataset

    struct Dataset: Decodable {
        var data: [PortfolioData]

        struct PortfolioData: Decodable {
            let date : String
            let value : Double

            init(from decoder: Decoder) throws {
                var container = try decoder.unkeyedContainer()
                date = try container.decode(String.self)
                value = try container.decode(Double.self)
            }
        }
    }
}

You can even decode the date strings as Date

struct PortfolioData: Decodable {
    let date : Date
    let value : Double

    init(from decoder: Decoder) throws {
        var container = try decoder.unkeyedContainer()
        date = try container.decode(Date.self)
        value = try container.decode(Double.self)
    }
}

if you add a date formatter to the decoder

let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(formatter)
let details2 = try decoder.decode(PortfolioResponseModel.self, from: Data(myJSONArray.utf8))

To add to this, there is a very good example of complex JSON parsing with arrays in particular here. I hope this helps those who are trying to use Codeable with larger, more realistic JSON data.

The overview is this: Imagine you had the following JSON format:

{
"meta": {
    "page": 1,
    "total_pages": 4,
    "per_page": 10,
    "total_records": 38
},
"breweries": [
    {
        "id": 1234,
        "name": "Saint Arnold"
    },
    {
        "id": 52892,
        "name": "Buffalo Bayou"
    }
]

}

This is a common format with the array nested inside. You could create a struct that encapsulates the entire response, accommodating arrays for the "breweries" key, similar to what you were asking above:

struct PagedBreweries : Codable {
struct Meta : Codable {
    let page: Int
    let totalPages: Int
    let perPage: Int
    let totalRecords: Int
    enum CodingKeys : String, CodingKey {
        case page
        case totalPages = "total_pages"
        case perPage = "per_page"
        case totalRecords = "total_records"
    }
}

struct Brewery : Codable {
    let id: Int
    let name: String
}

let meta: Meta
let breweries: [Brewery]

}

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!