I am currently trying to encode a generic struct ( T
) which has an attribute of this type with 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)
This results in a JSON like this:
{
"id" : 1,
"attribute" : {
"name" : "name",
"age" : 29
}
}
But i would like to customize the encoding to get the nested attributes to the root level:
{
"id" : 1,
"name" : "name",
"age" : 29
}
Using a custom CodingKey
struct didn't work for me because T
might have any number of attributes and the keys (names of attributes) are not known in advance.
This would need to be done manually, by implementing encode(to:)
and 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)
}
}
Note, that this is a very brittle solution. I WOULD NOT recommend encoding it the way you planned. .
It easily breaks at run-time, with an error: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
, if T
's encoding container differs from A
's (which is a keyed container )
For example, the following fails at run-time:
let a = A(id: 1, attribute: "A")
let data = JSONEncoder().encode(a)
This is because when T
is a String
, its container is a SingleValueEncodingContainer
. Same would happen if T
was an array:
let a = A(id: 1, attribute: ["A"])
because an array is encoded with an UnkeyedEncodingContainer
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.