使用JSON、Swift 4.1编码关键困难

使用JSON、Swift 4.1编码关键困难,json,swift,codable,Json,Swift,Codable,我有一个JSON,其响应体如下所示: { "Count": 116, "Message": "Result returned successfully", "SearchCriteria": "Search Criteria", "Results": [ { "Value": "", "ValueId": "", "Variable": "Suggested VIN",

我有一个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"
    }
}
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)
    }
}
在没有编译器抱怨的情况下,我尝试用以下代码对其进行解码:

// 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)
    }
这导致了此
错误

keyNotFound(编码键(stringValue:“count”,intValue:nil), Swift.DecodingError.Context(编码路径:[],调试说明:“否 与键编码键关联的值(stringValue:“count\”,intValue: nil)(“count\”,underyingError:nil))无法读取数据 因为它不见了

工作,但可怕的企图 为了“继续前进”,我尝试了以下方法,并且能够解析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(来自解码器:)
,因此我重构如下:

{
    "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"
    }
}
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(来自解码器:)
中出现错误:

调用中的额外参数“valueID”


我不知道我的错误在哪里。如果你有建议,我欢迎你的意见。感谢阅读。

您的枚举必须称为codingkey,并且它们的大小写名称必须与结构属性的名称匹配(例如,
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"
    }
}

您使用的是哪个Swift版本?不确定这是否有帮助,但看起来他们已经使用Swift 4.1-@LucaAngeletti 4对可编码协议进行了一些更新。1@LucaAngeletti在问题的标题里。谢谢!我应该离开5分钟。为什么我的代码运行正常,而我没有特别使用“编码键”?我使用诸如MessageKeys、ChatKeys等自定义名称@tymac,因为您还提供了一个
init(from:)