如何在 Swift 4 中用 codable 解码 JSON?
How to decode JSON with codable in Swift 4?
我在使用 Codable
解码 JSON 时遇到了很大的问题
我收到错误消息
Thread 1: Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.keyNotFound(SpecieKeys(stringValue: "v", intValue: nil), Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key SpecieKeys(stringValue: \"v\", intValue: nil) (\"v\").", underlyingError: nil))
我花了很多时间,但我不明白为什么.. :-(
这是我的json
let myJson = """
[{"i":"4","p":"4","l":["Ail"],"ll":["Allium sativum L."]},
{"i":"20.1","l":["Artichaut"],"ll":["Cynara cardunculus"]},
{"i":"XX.3",
"l":["Tomate cerise"],
"ll":["Solanum humboldtii"],
"v":[{"s":1,
"i":"0",
"l":"Orange Grape Tress",
"c":"Orange",
"h":992,
"ss":12
}]
}]
"""
let jsonDATA = myJson.data(using: .utf8)!
和我的结构
struct Specie : Decodable {
var id : String?
var name : [String]?
var latinName : [String]?
var varieties : [Variety]?
// keys
enum SpecieKeys: String, CodingKey {
case id = "i"
case name = "l"
case latinName = "ll"
case varieties = "v"
}
struct Variety : Decodable {
var source : Int?
var id : String?
var color : String?
var name : String?
var photo : String?
var harvest : Int?
var semiShelter : Int?
var semiOutside : Int?
// keys
enum VarietyKeys: String, CodingKey {
case id = "i"
case source = "s"
case color = "c"
case photo = "p"
case harvest = "h"
case semiShelter = "ss"
case semiOutside = "so"
case name = "l"
}
init(from decoder: Decoder) throws
{
let vValues = try decoder.container(keyedBy: VarietyKeys.self)
id = try vValues.decode(String.self, forKey: .id)
source = try vValues.decode(Int.self, forKey: .source)
name = try vValues.decode(String.self, forKey: .name)
color = try vValues.decode(String.self, forKey: .color)
photo = try vValues.decode(String.self, forKey: .photo)
harvest = try vValues.decode(Int.self, forKey: .harvest)
semiShelter = try vValues.decode(Int.self, forKey: .semiShelter)
semiOutside = try vValues.decode(Int.self, forKey: .semiOutside)
}
}
init(from decoder: Decoder) throws
{
let sValues = try decoder.container(keyedBy: SpecieKeys.self)
id = try sValues.decode(String.self, forKey: .id)
name = try sValues.decode(Array<String>.self, forKey: .name)
latinName = try sValues.decode(Array<String>.self, forKey: .latinName)
varieties = try sValues.decode(Array<Variety>.self, forKey: .varieties)
}
}
最后一个密码
var jsonResult = [Specie]()
jsonResult = try! JSONDecoder().decode(Array<Specie>.self, from: jsonDATA)
有人可以帮我解决我的错误。
对于每个可选值,您必须使用 decodeIfPresent(:forKey) instead of decode(:forKey)。当 decode(_:forKey)
找到 nil
值 ("No value associated with key ..."
)
时,您的解析将失败
但是,更简单的解决方案是让编译器生成您的解码初始值设定项:
struct Specie : Decodable {
var id : String?
var name : [String]?
var latinName : [String]?
var varieties : [Variety]?
// keys
enum CodingKeys: String, CodingKey {
case id = "i"
case name = "l"
case latinName = "ll"
case varieties = "v"
}
struct Variety : Decodable {
var source : Int?
var id : String?
var color : String?
var name : String?
var photo : String?
var harvest : Int?
var semiShelter : Int?
var semiOutside : Int?
// keys
enum CodingKeys: String, CodingKey {
case id = "i"
case source = "s"
case color = "c"
case photo = "p"
case harvest = "h"
case semiShelter = "ss"
case semiOutside = "so"
case name = "l"
}
}
}
唯一需要做的就是将您的密钥枚举重命名为 CodingKeys
,以便编译器可以识别它们。
我在使用 Codable
解码 JSON 时遇到了很大的问题我收到错误消息
Thread 1: Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.keyNotFound(SpecieKeys(stringValue: "v", intValue: nil), Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key SpecieKeys(stringValue: \"v\", intValue: nil) (\"v\").", underlyingError: nil))
我花了很多时间,但我不明白为什么.. :-(
这是我的json
let myJson = """
[{"i":"4","p":"4","l":["Ail"],"ll":["Allium sativum L."]},
{"i":"20.1","l":["Artichaut"],"ll":["Cynara cardunculus"]},
{"i":"XX.3",
"l":["Tomate cerise"],
"ll":["Solanum humboldtii"],
"v":[{"s":1,
"i":"0",
"l":"Orange Grape Tress",
"c":"Orange",
"h":992,
"ss":12
}]
}]
"""
let jsonDATA = myJson.data(using: .utf8)!
和我的结构
struct Specie : Decodable {
var id : String?
var name : [String]?
var latinName : [String]?
var varieties : [Variety]?
// keys
enum SpecieKeys: String, CodingKey {
case id = "i"
case name = "l"
case latinName = "ll"
case varieties = "v"
}
struct Variety : Decodable {
var source : Int?
var id : String?
var color : String?
var name : String?
var photo : String?
var harvest : Int?
var semiShelter : Int?
var semiOutside : Int?
// keys
enum VarietyKeys: String, CodingKey {
case id = "i"
case source = "s"
case color = "c"
case photo = "p"
case harvest = "h"
case semiShelter = "ss"
case semiOutside = "so"
case name = "l"
}
init(from decoder: Decoder) throws
{
let vValues = try decoder.container(keyedBy: VarietyKeys.self)
id = try vValues.decode(String.self, forKey: .id)
source = try vValues.decode(Int.self, forKey: .source)
name = try vValues.decode(String.self, forKey: .name)
color = try vValues.decode(String.self, forKey: .color)
photo = try vValues.decode(String.self, forKey: .photo)
harvest = try vValues.decode(Int.self, forKey: .harvest)
semiShelter = try vValues.decode(Int.self, forKey: .semiShelter)
semiOutside = try vValues.decode(Int.self, forKey: .semiOutside)
}
}
init(from decoder: Decoder) throws
{
let sValues = try decoder.container(keyedBy: SpecieKeys.self)
id = try sValues.decode(String.self, forKey: .id)
name = try sValues.decode(Array<String>.self, forKey: .name)
latinName = try sValues.decode(Array<String>.self, forKey: .latinName)
varieties = try sValues.decode(Array<Variety>.self, forKey: .varieties)
}
}
最后一个密码
var jsonResult = [Specie]()
jsonResult = try! JSONDecoder().decode(Array<Specie>.self, from: jsonDATA)
有人可以帮我解决我的错误。
对于每个可选值,您必须使用 decodeIfPresent(:forKey) instead of decode(:forKey)。当 decode(_:forKey)
找到 nil
值 ("No value associated with key ..."
)
但是,更简单的解决方案是让编译器生成您的解码初始值设定项:
struct Specie : Decodable {
var id : String?
var name : [String]?
var latinName : [String]?
var varieties : [Variety]?
// keys
enum CodingKeys: String, CodingKey {
case id = "i"
case name = "l"
case latinName = "ll"
case varieties = "v"
}
struct Variety : Decodable {
var source : Int?
var id : String?
var color : String?
var name : String?
var photo : String?
var harvest : Int?
var semiShelter : Int?
var semiOutside : Int?
// keys
enum CodingKeys: String, CodingKey {
case id = "i"
case source = "s"
case color = "c"
case photo = "p"
case harvest = "h"
case semiShelter = "ss"
case semiOutside = "so"
case name = "l"
}
}
}
唯一需要做的就是将您的密钥枚举重命名为 CodingKeys
,以便编译器可以识别它们。