Open peterent opened 3 years ago
Unfortunately, you have to implement init(from decoder:)
and encode
functions manually when using classes with inheritance, this is how Codable
works. This is also the case for JSONDecoder
.
A workaround could be to use composition instead of inheritance:
struct Person: Codable {
let nameDetails: NameDetails
let address: Address
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
nameDetails = try container.decode(NameDetails.self)
address = try container.decode(Address.self)
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(nameDetails)
try container.encode(address)
}
}
struct NameDetails: Codable {
var firstName: String?
var lastName: String?
}
struct Address: Codable {
var address: String?
}
let personJSON = #"{ "firstName": "Peter", "address": "Atlanta, Georgia, USA" }"#.data(using: .utf8)!
let addressJSON = #"{ "address": "London, United Kingdom" }"#.data(using: .utf8)!
let decoder = JSONDecoder()
let person = try! decoder.decode(Person.self, from: personJSON)
let address = try! decoder.decode(Address.self, from: addressJSON)
This way you'd only need to maintain custom Codable
implementation only for the base Person
type, while any fields added to NameDetails
or Address
would be handled automatically. And you could use either NameDetails
or Address
instead of Person
if you need to parse just corresponding subsets of fields. I'm using JSON as an example here, but I would expect it to work the same with XMLCoder.
@peterent does that help with your issue?
Another option is to declare custom Codable
conformance in your derived MyAddress
class as shown in this SO answer. But you still have to tell the decoder that you're decoding MyAddress
upfront, it won't be able to figure out whether to decode a base class or a derived class dynamically.
@MaxDesiatov Another question related to Class vs Struct. I've got decoding working with a class but when i change that class to a struct, the decoding no longer works. Why would that be?
It's very hard to say without looking at the actual code. Do you have an isolated reproducible test case for this?
I'll try to set something up.
Let's say I have this simple XML:
And I wish to decode it into the following Swift classes:
I've set up set up a function like this:
When I call it as follows:
It only parses the MyBase class (
firstName
andlastName
), ignoringaddress
in the MyAddress class. Why is that?I can work around this by using
CodingKeys
and implementingencode
anddecode
functions, but I shouldn't have to, right?Or am I missing something?