【问题标题】:Map JSON date keys to a struct in Swift 4将 JSON 日期键映射到 Swift 4 中的结构
【发布时间】:2018-07-08 17:02:49
【问题描述】:

我正在尝试解析这个 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


}

对于元数据部分,它运行良好。 但是对于时间序列部分,我不知道如何在不迭代时间序列数据的情况下超越日期。

我想知道是否有办法将此部分映射到结构:

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

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

【问题讨论】:

    标签: json struct swift4


    【解决方案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 }
        }
    }
    

    【讨论】:

    • 谢谢,真的很棒。还有一个问题:除了有一个数组 [Prices] 之外,是否可以映射到每个数组:开盘价、最高价、最低价、收盘价?
    • 对不起,我不明白。 映射到每个是什么?
    • 我的意思是让每个价格变量都成为 Price: price.open 等的成员。就像我在 Meta 中一样:stocks.metaData.symbol
    • 我还是不明白。 open, high, low, closePrice 的成员,而键 TimeSeries 的值实际上是一个数组。
    • 抱歉我是个菜鸟 :-) 我可以执行以下 print(stocks.metaData.symbol) 但不能: print(stocks.price.open) 我收到一条错误消息:Value of type ' ViewController.Stocks'没有成员'price';你是说“价格”吗?
    猜你喜欢
    • 2015-06-27
    • 1970-01-01
    • 1970-01-01
    • 2019-06-07
    • 2018-07-30
    • 2018-01-20
    • 2018-07-18
    • 2023-04-05
    • 2012-09-09
    相关资源
    最近更新 更多