I am trying to decode an object like MyPets
with the following object below. I tried using 4 CodingKeys cat, dog, catName and dogName but since the names are not in the MyPets struct, they aren't available to decode and then join with the others to fill out the Dog
and Cat
structs. I also tried a nestedContainer for the name properties with no luck. Any ideas? Thank you!
struct MyPets: Decodable {
let dog: Dog
let cat: Cat
// enum CodingKeys: String, CodingKey {
// case dog
// case cat
// case catName
// case dogName
// }
public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
// values only has dog and cat
}
}
struct Dog {
let name: String
let weight: Int
let food: String
}
struct Cat {
let name: String
let weight: Int
let food: String
}
With the following object:
{
"catName": "fluffy",
"dogName": "softy",
"cat": {
"food": "fancyFeast",
"weight": "8"
},
"dog": {
"food": "kibble",
"weight": "9"
}
}
I want to do something like this to recreate the Cat struct
let catName = (try values.decode(String.self, forKey: .catName))
self.cat = Cat(name: catName, etc...)
CodePudding user response:
This can be used by having two different CodingKey
enums, one for the actual properties and one that we decode to local variables.
struct MyPets: Decodable {
var dog: Dog
var cat: Cat
enum CodingKeys: String, CodingKey {
case dog
case cat
}
enum HiddenKeys: String, CodingKey {
case dogName
case catName
}
Then we make use of them in init(from:)
by creating two different containers
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
dog = try container.decode(Dog.self, forKey: .dog)
cat = try container.decode(Cat.self, forKey: .cat)
let otherContainer = try decoder.container(keyedBy: HiddenKeys.self)
let dogName = try otherContainer.decode(String.self, forKey: .dogName)
let catName = try otherContainer.decode(String.self, forKey: .catName)
self.dog.name = dogName
self.cat.name = catName
}
Dog
and Cat
(not shown here) needs to conform to Decodable
as well and use their own CodingKey
enum
struct Dog: Decodable {
var name: String = ""
let weight: Int
let food: String
enum CodingKeys: String, CodingKey {
case weight, food
}
}