使用 Swift4 Codable 解码数组
Decoding an Array with Swift4 Codable
我又在玩 Swift 4 Codable,就在我认为我掌握了它的窍门时,我在从响应中解码天气键时遇到了这个问题。
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}
"""
Swift 型号:
//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)
}
}
我不确定我做错了什么。其他一切都完美地解码到我的模型中。仅当我尝试解码数组时。有什么建议吗?
您错误地解码了 weather
密钥。它是顶级密钥,因此您无需创建子容器。够了:
self.weather = try container.decode([WeatherObj].self, forKey: .weather)
但是我实际上建议您创建一个非常接近 JSON 的 private struct
以简化解码过程。然后就可以挑出你要初始化数据模型的部分了:
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
}
}
我又在玩 Swift 4 Codable,就在我认为我掌握了它的窍门时,我在从响应中解码天气键时遇到了这个问题。
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}
"""
Swift 型号:
//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)
}
}
我不确定我做错了什么。其他一切都完美地解码到我的模型中。仅当我尝试解码数组时。有什么建议吗?
您错误地解码了 weather
密钥。它是顶级密钥,因此您无需创建子容器。够了:
self.weather = try container.decode([WeatherObj].self, forKey: .weather)
但是我实际上建议您创建一个非常接近 JSON 的 private struct
以简化解码过程。然后就可以挑出你要初始化数据模型的部分了:
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
}
}