JSON、Swift 4.1 的编码关键困难
Coding Key difficulties with JSON, Swift 4.1
我有一个 JSON 的响应正文如下所示:
{
"Count": 116,
"Message": "Result returned successfully",
"SearchCriteria": "Search Criteria",
"Results": [
{
"Value": "",
"ValueId": "",
"Variable": "Suggested VIN",
"VariableId": 142
},
< 115 more like this >
]
}
初次尝试
我最初尝试创建编码密钥,如下所示:
struct ResponseBody: Codable {
var count: Int
var message: String
var searchCriteria: String
var results: [Result]
enum ResponseKeys: String, CodingKey {
case count = "Count"
case message = "Message"
case searchCriteria = "SearchCriteria"
case results = "Results"
}
}
struct Result: Codable {
var value: String?
var valueId: String?
var variable: String
var variableId: Int
enum ResultKeys: String, CodingKey {
case value = "Value"
case valueID = "ValueId"
case variable = "Variable"
case variableID = "VariableId"
}
}
没有编译器的抱怨,我尝试用这段代码解码它:
// network request code
let decoder = JSONDecoder()
var responseData: ResponseBody?
do {
responseData = try decoder.decode(ResponseBody.self, from: data)
guard let responseData = responseData else { return }
let vehicle = self.createVehicleStruct(from: responseData)
self.dispatchGroup.notify(queue: .main, execute: {
completion(vehicle)
})
} catch {
print(error, error.localizedDescription)
}
产生了这个 error
:
keyNotFound(CodingKeys(stringValue: "count", intValue: nil),
Swift.DecodingError.Context(codingPath: [], debugDescription: "No
value associated with key CodingKeys(stringValue: \"count\", intValue:
nil) (\"count\").", underlyingError: nil)) The data couldn’t be read
because it is missing.
工作,但可怕的尝试
渴望 "get on down the road",我尝试了以下方法并且能够解析 JSON,但是不符合 Swift 命名约定让我很生气:
struct ResponseBody: Codable {
var Count: Int
var Message: String
var SearchCriteria: String
var Results: [Result]
}
struct Result: Codable {
var Value: String?
var ValueId: String?
var Variable: String
var VariableId: Int
}
现在,我又开始尝试在我的 structs
中获得漂亮、干净的名字,因为我知道网络部分可以正常工作。进一步调查,我需要提供一个init(from decoder:)
,所以我重构如下:
struct ResponseBody: Decodable {
var count: Int
var message: String
var searchCriteria: String
var results: [Result]
private enum CodingKeys: String, CodingKey {
case count = "Count"
case message = "Message"
case searchCriteria = "SearchCriteria"
case results = "Results"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let count: Int = try container.decode(Int.self, forKey: .count)
let message: String = try container.decode(String.self, forKey: .message)
let searchCriteria: String = try container.decode(String.self, forKey: .searchCriteria)
let results: [Result] = try container.decode([Result].self, forKey: .results)
// FIXME: Extra argument 'message' in call
self.init(count: count, message: message, searchCriteria: searchCriteria, results: [results])
}
}
struct Result: Decodable {
var value: String?
var valueID: String?
var variable: String
var variableID: Int
private enum CodingKeys: String, CodingKey {
case value = "Value"
case valueID = "ValueId"
case variable = "Variable"
case variableID = "VariableId"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let value: String = try container.decode(String.self, forKey: .value)
let valueID: String = try container.decode(String.self, forKey: .valueID)
let variable: String = try container.decode(String.self, forKey: .variable)
let variableID: Int = try container.decode(Int.self, forKey: .variableID)
// FIXME: Extra argument 'valueID' in call
self.init(value: value?, valueID: valueID?, variable: variable, variableID: variableID)
}
}
当我调用 init:
时,我在 init(from decoder:)
中遇到错误
Extra argument 'valueID' in call
我想不通我的错误在哪里。如果您有任何建议,我欢迎您的意见。感谢阅读。
您的枚举必须称为 CodingKeys,并且它们的 case 名称必须与结构属性的名称匹配(例如 variableID
和 variableId
不相同,但它们必须相同)。
一旦你解决了这个问题,一切都会好起来的。
因此我能够解析您提供的 JSON,没问题,使用这两个结构:
struct ResponseBody: Codable {
var count: Int
var message: String
var searchCriteria: String
var results: [Result]
enum CodingKeys: String, CodingKey {
case count = "Count"
case message = "Message"
case searchCriteria = "SearchCriteria"
case results = "Results"
}
}
struct Result: Codable {
var value: String?
var valueId: String?
var variable: String
var variableId: Int
enum CodingKeys: String, CodingKey {
case value = "Value"
case valueId = "ValueId"
case variable = "Variable"
case variableId = "VariableId"
}
}
我有一个 JSON 的响应正文如下所示:
{
"Count": 116,
"Message": "Result returned successfully",
"SearchCriteria": "Search Criteria",
"Results": [
{
"Value": "",
"ValueId": "",
"Variable": "Suggested VIN",
"VariableId": 142
},
< 115 more like this >
]
}
初次尝试
我最初尝试创建编码密钥,如下所示:
struct ResponseBody: Codable {
var count: Int
var message: String
var searchCriteria: String
var results: [Result]
enum ResponseKeys: String, CodingKey {
case count = "Count"
case message = "Message"
case searchCriteria = "SearchCriteria"
case results = "Results"
}
}
struct Result: Codable {
var value: String?
var valueId: String?
var variable: String
var variableId: Int
enum ResultKeys: String, CodingKey {
case value = "Value"
case valueID = "ValueId"
case variable = "Variable"
case variableID = "VariableId"
}
}
没有编译器的抱怨,我尝试用这段代码解码它:
// network request code
let decoder = JSONDecoder()
var responseData: ResponseBody?
do {
responseData = try decoder.decode(ResponseBody.self, from: data)
guard let responseData = responseData else { return }
let vehicle = self.createVehicleStruct(from: responseData)
self.dispatchGroup.notify(queue: .main, execute: {
completion(vehicle)
})
} catch {
print(error, error.localizedDescription)
}
产生了这个 error
:
keyNotFound(CodingKeys(stringValue: "count", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"count\", intValue: nil) (\"count\").", underlyingError: nil)) The data couldn’t be read because it is missing.
工作,但可怕的尝试
渴望 "get on down the road",我尝试了以下方法并且能够解析 JSON,但是不符合 Swift 命名约定让我很生气:
struct ResponseBody: Codable {
var Count: Int
var Message: String
var SearchCriteria: String
var Results: [Result]
}
struct Result: Codable {
var Value: String?
var ValueId: String?
var Variable: String
var VariableId: Int
}
现在,我又开始尝试在我的 structs
中获得漂亮、干净的名字,因为我知道网络部分可以正常工作。进一步调查,我需要提供一个init(from decoder:)
,所以我重构如下:
struct ResponseBody: Decodable {
var count: Int
var message: String
var searchCriteria: String
var results: [Result]
private enum CodingKeys: String, CodingKey {
case count = "Count"
case message = "Message"
case searchCriteria = "SearchCriteria"
case results = "Results"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let count: Int = try container.decode(Int.self, forKey: .count)
let message: String = try container.decode(String.self, forKey: .message)
let searchCriteria: String = try container.decode(String.self, forKey: .searchCriteria)
let results: [Result] = try container.decode([Result].self, forKey: .results)
// FIXME: Extra argument 'message' in call
self.init(count: count, message: message, searchCriteria: searchCriteria, results: [results])
}
}
struct Result: Decodable {
var value: String?
var valueID: String?
var variable: String
var variableID: Int
private enum CodingKeys: String, CodingKey {
case value = "Value"
case valueID = "ValueId"
case variable = "Variable"
case variableID = "VariableId"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let value: String = try container.decode(String.self, forKey: .value)
let valueID: String = try container.decode(String.self, forKey: .valueID)
let variable: String = try container.decode(String.self, forKey: .variable)
let variableID: Int = try container.decode(Int.self, forKey: .variableID)
// FIXME: Extra argument 'valueID' in call
self.init(value: value?, valueID: valueID?, variable: variable, variableID: variableID)
}
}
当我调用 init:
时,我在init(from decoder:)
中遇到错误
Extra argument 'valueID' in call
我想不通我的错误在哪里。如果您有任何建议,我欢迎您的意见。感谢阅读。
您的枚举必须称为 CodingKeys,并且它们的 case 名称必须与结构属性的名称匹配(例如 variableID
和 variableId
不相同,但它们必须相同)。
一旦你解决了这个问题,一切都会好起来的。
因此我能够解析您提供的 JSON,没问题,使用这两个结构:
struct ResponseBody: Codable {
var count: Int
var message: String
var searchCriteria: String
var results: [Result]
enum CodingKeys: String, CodingKey {
case count = "Count"
case message = "Message"
case searchCriteria = "SearchCriteria"
case results = "Results"
}
}
struct Result: Codable {
var value: String?
var valueId: String?
var variable: String
var variableId: Int
enum CodingKeys: String, CodingKey {
case value = "Value"
case valueId = "ValueId"
case variable = "Variable"
case variableId = "VariableId"
}
}