Swift 4解码复杂嵌套JSON
Swift 4 decode complex nested JSON
我正在尝试创建一个更清晰的可编码结构,在其中我可以通过键入 day.description
而不是 day.weather.description
来访问 "description"
描述值嵌套在一个只包含一个对象的数组"weather"中。我想从索引 0 中提取描述并将其分配给我的结构中的描述。
这是我正在使用的 JSON:
{
"dt": 1558321200,
"main": {
"temp": 11.88,
"temp_min": 11.88,
"temp_max": 11.88,
"pressure": 1013.3,
"sea_level": 1013.3,
"grnd_level": 1003.36,
"humidity": 77,
"temp_kf": 0
},
"weather": [{
"id": 800,
"main": "Clear",
"description": "clear sky",
"icon": "01n"
}],
"clouds": {
"all": 0
},
"wind": {
"speed": 5.58,
"deg": 275.601
},
"sys": {
"pod": "n"
},
"dt_txt": "2019-05-20 03:00:00"
}
以及我目前拥有的代码:
struct Weather: Codable {
let days: [Day]
enum CodingKeys: String, CodingKey {
case days = "list"
}
}
struct Day: Codable {
let date: String
let main: Main
let wind: Wind
let description: String
enum CodingKeys: String, CodingKey {
case date = "dt_txt"
case main
case wind
case weather
case description
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
date = try container.decode(String.self, forKey: .date)
main = try container.decode(Main.self, forKey: .main)
wind = try container.decode(Wind.self, forKey: .wind)
let weather = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .weather)
description = try weather.decode(String.self, forKey: .description)
}
}
如您所知,最简单的方法就是计算 属性 并引用所需的值。但是,为了完整起见,我们不妨讨论如何做您实际要求做的事情。让我们用你的 JSON:
的简化版本来说明
{
"dt": 1558321200,
"weather": [{
"id": 800,
"main": "Clear",
"description": "clear sky",
"icon": "01n"
}]
}
所以问题是,我们如何将其解析为具有 description
属性 的结构结果,以便我们从第一项中取出 "description"
键在 "weather"
数组中?这是一种方法:
struct Result : Decodable {
let description : String
enum Keys : CodingKey {
case weather
}
struct Weather : Decodable {
let description : String
}
init(from decoder: Decoder) throws {
let con = try! decoder.container(keyedBy: Keys.self)
var arr = try! con.nestedUnkeyedContainer(forKey: .weather) // weather array
let oneWeather = try! arr.decode(Weather.self) // decode first element
self.description = oneWeather.description
}
}
基本上这里的想法是 nestedUnkeyedContainer
给了我们数组,随后对该数组的 decode
调用自动依次处理每个元素。我们只有一个元素,所以我们只需要一个 decode
调用。我们如何处理结果字符串取决于我们,所以现在我们可以将它插入我们的 top-level description
属性.
但这是另一种方法。我们甚至不需要二级 Weather 结构;我们可以直接进入 "weather"
数组并获取第一个字典元素并访问它的 "description"
键,而无需再说明该内部字典中的内容,如下所示:
struct Result : Decodable {
let description : String
enum Keys : CodingKey {
case weather
case description
}
init(from decoder: Decoder) throws {
let con = try! decoder.container(keyedBy: Keys.self)
var arr = try! con.nestedUnkeyedContainer(forKey: .weather)
let con2 = try! arr.nestedContainer(keyedBy: Keys.self)
let desc = try! con2.decode(String.self, forKey: .description)
self.description = desc
}
}
你的问题不是很完整(你没有展示你的真实 JSON,只是摘录),所以我无法给出更准确的建议,但我相信您可以看到如何根据您的需要调整此技术。
我正在尝试创建一个更清晰的可编码结构,在其中我可以通过键入 day.description
而不是 day.weather.description
描述值嵌套在一个只包含一个对象的数组"weather"中。我想从索引 0 中提取描述并将其分配给我的结构中的描述。
这是我正在使用的 JSON:
{
"dt": 1558321200,
"main": {
"temp": 11.88,
"temp_min": 11.88,
"temp_max": 11.88,
"pressure": 1013.3,
"sea_level": 1013.3,
"grnd_level": 1003.36,
"humidity": 77,
"temp_kf": 0
},
"weather": [{
"id": 800,
"main": "Clear",
"description": "clear sky",
"icon": "01n"
}],
"clouds": {
"all": 0
},
"wind": {
"speed": 5.58,
"deg": 275.601
},
"sys": {
"pod": "n"
},
"dt_txt": "2019-05-20 03:00:00"
}
以及我目前拥有的代码:
struct Weather: Codable {
let days: [Day]
enum CodingKeys: String, CodingKey {
case days = "list"
}
}
struct Day: Codable {
let date: String
let main: Main
let wind: Wind
let description: String
enum CodingKeys: String, CodingKey {
case date = "dt_txt"
case main
case wind
case weather
case description
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
date = try container.decode(String.self, forKey: .date)
main = try container.decode(Main.self, forKey: .main)
wind = try container.decode(Wind.self, forKey: .wind)
let weather = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .weather)
description = try weather.decode(String.self, forKey: .description)
}
}
如您所知,最简单的方法就是计算 属性 并引用所需的值。但是,为了完整起见,我们不妨讨论如何做您实际要求做的事情。让我们用你的 JSON:
的简化版本来说明{
"dt": 1558321200,
"weather": [{
"id": 800,
"main": "Clear",
"description": "clear sky",
"icon": "01n"
}]
}
所以问题是,我们如何将其解析为具有 description
属性 的结构结果,以便我们从第一项中取出 "description"
键在 "weather"
数组中?这是一种方法:
struct Result : Decodable {
let description : String
enum Keys : CodingKey {
case weather
}
struct Weather : Decodable {
let description : String
}
init(from decoder: Decoder) throws {
let con = try! decoder.container(keyedBy: Keys.self)
var arr = try! con.nestedUnkeyedContainer(forKey: .weather) // weather array
let oneWeather = try! arr.decode(Weather.self) // decode first element
self.description = oneWeather.description
}
}
基本上这里的想法是 nestedUnkeyedContainer
给了我们数组,随后对该数组的 decode
调用自动依次处理每个元素。我们只有一个元素,所以我们只需要一个 decode
调用。我们如何处理结果字符串取决于我们,所以现在我们可以将它插入我们的 top-level description
属性.
但这是另一种方法。我们甚至不需要二级 Weather 结构;我们可以直接进入 "weather"
数组并获取第一个字典元素并访问它的 "description"
键,而无需再说明该内部字典中的内容,如下所示:
struct Result : Decodable {
let description : String
enum Keys : CodingKey {
case weather
case description
}
init(from decoder: Decoder) throws {
let con = try! decoder.container(keyedBy: Keys.self)
var arr = try! con.nestedUnkeyedContainer(forKey: .weather)
let con2 = try! arr.nestedContainer(keyedBy: Keys.self)
let desc = try! con2.decode(String.self, forKey: .description)
self.description = desc
}
}
你的问题不是很完整(你没有展示你的真实 JSON,只是摘录),所以我无法给出更准确的建议,但我相信您可以看到如何根据您的需要调整此技术。