使用Swift的Decodable协议解析CoinMarketCap API

爱迪生

我已经阅读了如何使用Swift Decodable协议解码嵌套的JSON结构?它没有解决我将字符串文字数字值用作根字典的特定用例。

另外,如何使用Swift Decodable协议解码嵌套的JSON结构?Imanou Petit的回答。无法从Leo Dabus的API答复中解码JSON数据

货币本身就是字典,由字典内的文字字符串数字表示,data因此这让我大吃一惊。我正在寻找使用枚举的最Swifty 4模型,在该模型中很容易看出哪些容器对应哪些字典。

ps大卫·贝里(David Berry)给出了一个很好的答案,下面我已经实现了。如果其他人有其他方法来获得相同的结果,我希望看到不同的建议。也许有一些尚不为人所知的更新的Swift 4方法或其他设计模式。

struct RawServerResponse {

    enum RootKeys: String, CodingKey {
        case data
        case btc = "1"
        case eth = "1027"
        case iota = "1720"
        case ripple = "52"
        case neo = "1376"
        case quotes
        case USD
    }

    enum BaseKeys: String, CodingKey {
        case id, name, symbol, maxSupply = "max_supply"
    }

    enum QuotesKeys: String, CodingKey {
        case USD
    }

    enum USDKeys: String, CodingKey {
        case price, marketCap = "market_cap"
    }

    let data: String
    let id: Int
    let name: String
    let symbol: String
    let maxSupply: Double
    let price: Double
    let marketCap: Double
}

extension RawServerResponse: Decodable {

    init(from decoder: Decoder) throws {
        // data
        let container = try decoder.container(keyedBy: RootKeys.self)
        data = try container.decode(String.self, forKey: .data)

        // id
        let idContainer = try container.nestedContainer(keyedBy: BaseKeys.self, forKey: .data)
        id = try idContainer.decode(Int.self, forKey: .id) 

        // price
        let priceContainer = try container.nestedContainer(keyedBy: USDKeys.self, forKey: .USD)
        price = try priceContainer.decode(Double.self, forKey: .price)

    }

}

API / JSON https://api.coinmarketcap.com/v2/ticker/

{
"data": {
    "1": {
        "id": 1, 
        "name": "Bitcoin", 
        "symbol": "BTC", 
        "website_slug": "bitcoin", 
        "rank": 1, 
        "circulating_supply": 17041575.0, 
        "total_supply": 17041575.0, 
        "max_supply": 21000000.0, 
        "quotes": {
            "USD": {
                "price": 8214.7, 
                "volume_24h": 5473430000.0, 
                "market_cap": 139991426153.0, 
                "percent_change_1h": 0.09, 
                "percent_change_24h": 2.29, 
                "percent_change_7d": -2.44
            }
        }, 
        "last_updated": 1526699671
    }, 
    "1027": {
        "id": 1027, 
        "name": "Ethereum", 
        "symbol": "ETH", 
        "website_slug": "ethereum", 
        "rank": 2, 
        "circulating_supply": 99524121.0, 
        "total_supply": 99524121.0, 
        "max_supply": null, 
        "quotes": {
            "USD": {
                "price": 689.891, 
                "volume_24h": 2166100000.0, 
                "market_cap": 68660795252.0, 
                "percent_change_1h": 0.13, 
                "percent_change_24h": 2.51, 
                "percent_change_7d": 2.54
            }
        }, 
        "last_updated": 1526699662
    }
}
戴维·贝里

我将采用一种更简单的方法来处理数据,将“数据”视为键化的,相同的响应的集合,同样,“引号”是行情的键控集合。

struct RawServerResponse : Decodable {
    enum Keys : String, CodingKey {
        case data = "data"
    }

    let data : [String:Base]
}

struct Base : Decodable {
    enum CodingKeys : String, CodingKey {
        case id = "id"
        case name = "name"
        case symbol = "symbol"
        case maxSupply = "max_supply"
        case quotes = "quotes"
    }

    let id : Int64
    let name : String
    let symbol : String
    let maxSupply : Double?
    let quotes : [String:Quote]
}

struct Quote : Decodable {
    enum CodingKeys : String, CodingKey {
        case price = "price"
        case marketCap = "market_cap"
    }

    let price :  Double
    let marketCap : Double
}

然后,如果您确实确实需要从那些更简单的结构中访问各个键值,则可以提供计算的访问器:

extension RawServerResponse {
    enum BaseKeys : String {
        case btc = "1"
        case eth = "1027"
    }

    var eth : Base? { return data[BaseKeys.eth.rawValue] }
    var btc : Base? { return data[BaseKeys.btc.rawValue] }
}

并且,同样可以为货币创建类似的访问器:

extension Base {
    enum Currencies : String {
        case usd = "USD"
    }

    var usd : Quote? { return quotes[Currencies.usd.rawValue]}
}

一旦您解决了该部分,那么原始问题中的此链接将向您显示如果需要的话如何展平结构。从本质上讲,它可以归结为将计算出的属性更改为let要在构造函数中设置的属性。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章