The behavior you're seeing here is that derived classes don't have protocol conformances re-synthesized by the compiler — i.e., your subtypes inherit encode(to:)
directly from your base class (and never encode their properties), and both MyClassOne
and MyClassTwo
inherit init(from:)
from your base class (and would never attempt to decode those properties, if they were present); MyClassThree
doesn't have this latter issue, because it overrides init(from:)
to decode the properties itself (though it does have a different problem*).
See:
- Inheriting from a Codable class - #3 by itaiferber
- [SR-4772] Classes conforming to Codable need to synthesize overrides instead of inheriting conformance · Issue #47349 · apple/swift · GitHub
You'll either need to
- Override
encode(to:)
andinit(from:)
on your derived classes to encode and decode the properties they expect, or - If you never expect to encode or decode your base class, do as @tera suggests and move the conformances down into your derived types. This does, however, mean that your base class wouldn't be able to conform to your protocol, which might have some lead-on effects
*Inside of an init(from:)
implementation, calling super.init(from: decoder)
is generally not recommended, unless you have very tight coupling between the parent and child class and have special knowledge in the child class about the parent class's implementation, as both the parent and child class attempt to decode out of the same decoding container.
This can be an issue because:
- A parent and child class must then use the same container type (e.g., both must be keyed or unkeyed identically), and
- If the child and parent class share a field with the same name, the parent class's handling of that field will override the child's
In the general case, it's recommended that you fetch a superEncoder(forKey:)
/superDecoder(forKey:)
to sequester the parent class into a nested container, then pass that along to the parent.