使用Swift4 Codable解码数组 [英] Decoding an Array with Swift4 Codable

查看:163
本文介绍了使用Swift4 Codable解码数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我再次使用Swift 4 Codable,就在我认为自己掌握了这个要诀时,我从响应中解码Weather键就遇到了这个问题.

I'm playing around with Swift 4 Codable again and just when I think I have the hang of it, I get this issue with decoding the Weather key from the response.

 let jsonData = """
    {"coord":{"lon":-113,"lat":35},
"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01n"}],
"base":"stations",
"main":{"temp":291.15,"pressure":1022,"humidity":72,"temp_min":291.15,"temp_max":291.15},
"visibility":16093,"wind":{"speed":3.6,"deg":200},
"clouds":{"all":1},
"dt":1503294780,"sys":{"type":1,"id":321,"message":0.184,"country":"US","sunrise":1503320222,"sunset":1503367937},
"id":5308281,"name":"Paulden","cod":200}
"""

快速模型:

//Top Level Container
struct Response: Codable {

    enum ResponseKeys: String, CodingKey {
        case name
        case code = "cod"
        case main
        case weather
    }
    //Nested Level Keys: Response > Weather
    enum WeatherKeys: String, CodingKey {
        case weather
    }
    //Nested Level Keys: Response > Main
    enum MainKeys: String, CodingKey {
        case temp
        case pressure
        case humidity
        case tempMin = "temp_min"
        case tempMax = "temp_max"
    }
    //Properties
    var name: String
    var code: Int
    var temp: Double
    var pressure: Int
    var weather:[WeatherObj]

    //Custom Init
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: ResponseKeys.self)
        let weatherContainer = try container.nestedContainer(keyedBy: WeatherKeys.self, forKey: .weather)
        let mainContainer = try container.nestedContainer(keyedBy: MainKeys.self, forKey: .main)
        self.name = try container.decode(String.self, forKey: .name)
        self.code = try container.decode(Int.self, forKey: .code)
        self.pressure = try mainContainer.decode(Int.self, forKey: .pressure)
        self.temp = try mainContainer.decode(Double.self, forKey: .temp)

        // Here is where it throws: the data couldn’t be read because it isn’t in the correct format
        self.weather = try weatherContainer.decode([WeatherObj].self, forKey: .weather)
    }
}

我不确定我做错了什么.其他所有内容都能完美地解码到我的模型中.只有当我尝试解码数组时.有什么建议吗?

I'm not sure what I'm not doing correctly. Everything else decodes into my model perfectly. It's only when I try to decode an Array. Any suggestions?

推荐答案

您错误地解码了weather密钥.这是一个顶级密钥,因此您无需创建子容器.足够了:

You decoded the weather key incorrectly. It's a top-level key so you don't need to create a subcontainer. This is enough:

self.weather = try container.decode([WeatherObj].self, forKey: .weather)


但是我实际上建议您创建一个非常接近JSON的private struct,以简化解码过程.然后,您可以选择要初始化数据模型的片段:


However I'd actually recommend that you create a private struct that stays very close to the JSON to ease the decoding process. Then you can pick off the pieces you want to initialize the data model:

struct Response: Codable {
    var name: String
    var code: Int
    var temp: Double
    var pressure: Int
    var weather: [WeatherObj]

    // This stays as close to the JSON as possible to minimize the amount of manual code
    // It uses snake_case and the JSON's spelling of "cod" for "code". Since it's private,
    // outside caller can never access it
    private struct RawResponse: Codable {
        var name: String
        var cod: Int
        var main: Main
        var weather: [WeatherObj]

        struct Main: Codable {
            var temp: Double
            var pressure: Int
        }
    }

    init(from decoder: Decoder) throws {
        let rawResponse = try RawResponse(from: decoder)

        // Now pick the pieces you want
        self.name     = rawResponse.name
        self.code     = rawResponse.cod
        self.temp     = rawResponse.main.temp
        self.pressure = rawResponse.main.pressure
        self.weather  = rawResponse.weather
    }
}

这篇关于使用Swift4 Codable解码数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆