我正在研究JSON编码和解码,但是有些问题非常烦人,我不知道如何在继承类中使用CodingKeys
。
我有两个班ResponseBean
和ResponseWithObjectBean<T>
。
这是响应类的定义:
public class ResponseBean: Codable
{
//This is only sample, I define `CodingKeys` because the property in json is in different name.
private enum CodingKeys: String, CodingKey
{
case intA
case intB
}
public var intA: Int32 = 0
public var intB: Int32 = 0
}
public class ResponseWithObjectBean<T: Codable> : ResponseBean
{
/*
Here I don't know how to define an enum to confirm protocl CondingKey.
I defined an enum named CodingKeys or whatever, they just don't work and
the testMessage and obj are still nil.
But if I implement the init(from decoder: Decoder) construction and manually
pass the coding keys which I defined to the decode function, all works fine.
*/
public var testMessage: String? = nil
public var obj: T? = nil
}
我将从响应中得到一个用户:
public class User: Codable
{
private enum CodingKeys: String, CodingKey
{
case name
case age
}
public var name: String? = nil
public var age: Int32? = nil
}
这是测试json:
var testJson = """
{
"intA": 10,
"intB": 20,
"testMessage": "This is a test json",
"obj":{
"name": "LiHong",
"age": 11
}
}
"""
以下是我的运行方式:
do{
var responseData = testJson.data(using: .utf8)
var decoder = JSONDecoder()
var response: ResponseWithObjectBean<User> = try decoder.decode(ResponseWithObjectBean<User>.self, from: responseData)
}catch let e{
}
我不知道如何在CodingKeys
类中定义ResponseWithObjectBean
,即使我这样做,它也根本不起作用。但是,如果我实现init(from decoder: Decoder) throws
的构造并手动传递在ResponseWithObjectBean
中定义的编码密钥,则可以获得所有属性。
答案 0 :(得分:0)
这非常简单,您只需要在子类中手动进行编码和解码即可:
public class ResponseWithObjectBean<T: Codable> : ResponseBean {
public var testMessage: String? = nil
public var obj: T? = nil
// Create another CodingKey compliant enum with another name for the new keys
private enum CustomCodingKeys: String, CodingKey {
case testMessage
case obj
}
// Override the decoder
required init(from decoder: Decoder) throws {
try super.init(from: decoder)
let container = try decoder.container(keyedBy: CustomCodingKeys.self)
testMessage = try container.decode(String?.self, forKey: .testMessage)
obj = try container.decode(T?.self, forKey: .obj)
}
// And the coder
public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CustomCodingKeys.self)
try container.encode(testMessage, forKey: .testMessage)
try container.encode(obj, forKey: .obj)
}
}
通过这种方式,您可以对所需的方式进行解码和编码:
let decoder = JSONDecoder()
let response = try decoder.decode(ResponseWithObjectBean<User>.self, from: responseData)
let data = try JSONEncoder().encode(response)
print(String(data: data, encoding: .utf8))
编辑:为了防止您手动编写所有此类样板,可以使用Sourcery等生成工具:https://github.com/krzysztofzablocki/Sourcery