我目前正在尝试使用T
对具有这种类型属性的通用结构(JSONEncoder
)进行编码:
struct A <T:Codable> : Codable {
var id: Int
var attribute : T
init(id: Int, attribute: T){
self.id = id
self.attribute = attribute
}
}
struct B : Codable {
var name: String
var age: Int
}
let encoder = JSONEncoder()
let foo = A<B>(id: 1, attribute: B(name: "name", age: 29))
try? encoder.encode(foo)
这将导致如下所示的JSON:
{
"id" : 1,
"attribute" : {
"name" : "name",
"age" : 29
}
}
但是我想自定义编码以使嵌套属性达到根级别:
{
"id" : 1,
"name" : "name",
"age" : 29
}
使用自定义CodingKey
结构对我不起作用,因为T
可能具有任意数量的属性,并且键(属性名称)事先未知。
答案 0 :(得分:3)
这需要通过实现encode(to:)
和init(from:)
来手动完成:
struct A <T:Codable> {
var id: Int
var attribute : T
}
extension A: Codable {
enum CodingKeys: CodingKey { case id }
func encode(to encoder: Encoder) throws {
// use attribute's own encode(to:)
try attribute.encode(to: encoder)
// then encode the id
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
}
init(from decoder: Decoder) throws {
// use attribute's own init(from:)
self.attribute = try T.init(from: decoder)
// decode the id
let container = try decoder.container(keyedBy: CodingKeys.self)
self.id = try container.decode(Int.self, forKey: .id)
}
}
请注意,这是一个非常脆弱的解决方案。我不建议按照您的计划进行编码。。
如果EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
的编码容器与T
的编码容器(是键容器< / em>)
例如,以下内容在运行时失败:
A
这是因为当let a = A(id: 1, attribute: "A")
let data = JSONEncoder().encode(a)
是T
时,其容器是String
。如果SingleValueEncodingContainer
是一个数组,也会发生同样的情况:
T
因为数组是用let a = A(id: 1, attribute: ["A"])
编码的