将JSON日期键映射到Swift 4中的结构

时间:2018-07-08 17:02:50

标签: json struct swift4

我正在尝试解析此JSON:

{
"MetaData": {
    "1. Information": "Daily Time Series with Splits and Dividend Events",
    "2. Symbol": "AAPL",
    "3. Last Refreshed": "2018-06-08",
    "4. Output Size": "Compact",
    "5. Time Zone": "US/Eastern"
},
"TimeSeries": {
    "2018-06-08": {
        "1. open": "191.1700",
        "2. high": "192.0000",
        "3. low": "189.7700",
        "4. close": "191.7000",
        "5. adjusted close": "191.7000",
        "6. volume": "26656799",
        "7. dividend amount": "0.0000",
        "8. split coefficient": "1.0000"
    },
    "2018-06-07": {
        "1. open": "194.1400",
        "2. high": "194.2000",
        "3. low": "192.3350",
        "4. close": "193.4600",
        "5. adjusted close": "193.4600",
        "6. volume": "21347180",
        "7. dividend amount": "0.0000",
        "8. split coefficient": "1.0000"
    },
    "2018-06-06": {
        "1. open": "193.6300",
        "2. high": "194.0800",
        "3. low": "191.9200",
        "4. close": "193.9800",
        "5. adjusted close": "193.9800",
        "6. volume": "20933619",
        "7. dividend amount": "0.0000",
        "8. split coefficient": "1.0000"
    },
        }
}

我想遵循这样的结构:

 struct Stocks: Decodable {
    struct Meta: Decodable {
        let info: String
        let symbol: String
        let last: String
        let size: String
        let time: String
        enum CodingKeys: String, CodingKey {
            case info = "1. Information"
            case symbol = "2. Symbol"
            case last = "3. Last Refreshed"
            case size = "4. Output Size"
            case time = "5. Time Zone"
        }
    }

    struct Time:  Decodable {
        let date: String
        let price = Prices()

        struct Prices: Decodable {
            var open: Int?
            var high: Int?
            var low: Int?
            var close: Int?
            enum  CodingKeys: String, CodingKey {
                case open = "1. open"
                case high = "2. high"
                case low = "3. low"
                case close = "4. close"
            }
        }
    }
    let MetaData: Meta
    let TimeSeries: Time


}

对于MetaData部分,它运行良好。 但是对于时间序列部分,我不知道如何跳过日期而不仅仅是遍历TimeSeries数据。

我想知道是否有一种方法可以将此部分映射到结构:

 "TimeSeries": {
    "2018-06-08": {
        "1. open": "191.1700",
        "2. high": "192.0000",
        "3. low": "189.7700",
        "4. close": "191.7000",
        "5. adjusted close": "191.7000",
        "6. volume": "26656799",
        "7. dividend amount": "0.0000",
        "8. split coefficient": "1.0000"
    },
    "2018-06-07": {
        "1. open": "194.1400",
        "2. high": "194.2000",
        "3. low": "192.3350",
        "4. close": "193.4600",
        "5. adjusted close": "193.4600",
        "6. volume": "21347180",
        "7. dividend amount": "0.0000",
        "8. split coefficient": "1.0000"
    },
    "2018-06-06": {
        "1. open": "193.6300",
        "2. high": "194.0800",
        "3. low": "191.9200",
        "4. close": "193.9800",
        "5. adjusted close": "193.9800",
        "6. volume": "20933619",
        "7. dividend amount": "0.0000",
        "8. split coefficient": "1.0000"
    },
        }
}

问题似乎是不断变化的日期键-如何将它们映射到结构上?

1 个答案:

答案 0 :(得分:1)

首先Prices中的值是String,请注意用双引号引起来。
并且即使这些值是数字,它们也将是Double,请注意小数点。

我的建议是编写一个自定义初始化程序,该初始化程序将键TimeSeries的值解码为字典,并将date键值对放入Price结构中(我使用的是单数形式)形成)。最后,该数组按date

排序
struct Stocks: Decodable {

    enum  CodingKeys: String, CodingKey { case timeSeries = "TimeSeries",  metaData = "MetaData"}

    struct Meta: Decodable {
        let info, symbol, last, size, time: String

        enum CodingKeys: String, CodingKey {
            case info = "1. Information"
            case symbol = "2. Symbol"
            case last = "3. Last Refreshed"
            case size = "4. Output Size"
            case time = "5. Time Zone"
        }
    }

    struct Price: Decodable {

        var date = ""
        let open, high, low, close: String

        enum  CodingKeys: String, CodingKey {
            case open = "1. open"
            case high = "2. high"
            case low = "3. low"
            case close = "4. close"
        }
    }

    let metaData: Meta
    let prices : [Price]

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        metaData = try container.decode(Meta.self, forKey: .metaData)
        let timeData = try container.decode([String:Price].self, forKey: .timeSeries)
        prices = timeData.map({ (key, value) -> Price in
            var newPrice = value
            newPrice.date = key
            return newPrice
        }).sorted { $0.date < $1.date }
    }
}