I recently came across a behaviour when using propertyWrappers with the Codable protocol which I find strange, so I wanted to ask if that is intended. So lets assume I have a model as follows:
struct Person: Codable {
var name: String?
}
The following can be decoded without a problem with the compiler synthesised Decodable implementation:
{
}
Now I want to use a simple propertyWrapper as follows:
@propertyWrapper
struct Passthrough<T: Codable>: Codable {
var wrappedValue: T
}
Applying the propertyWrapper to my model as follows:
struct Person: Codable {
@Passthrough var name: String?
}
Now if I try to decode the payload again it fails with the error:
keyNotFound(CodingKeys(stringValue: "name", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"name\", intValue: nil)
I am wondering if that's a bug because my expectation was that the decoding would apply to the wrappedValue type, if not is there a way to make the described scenario work without having to manually implement the initialiser of Person?
UPDATE:
Even if I manually implement Codable, the Decodable architecture treats the propertyWrapper as if I wanted to decode the propertyWrapper, but that's not what I want.
Here is what I came up with:
I agree that using @propertyWrapper is a great way to customise the behaviour of Codable in a declarative manner. There are a few tricks required which make sense when you think about what the compiler is doing for us.
The wrapper must conform to Codable because it is encoded and decoded, but you probably would like to omit its synthesised container from encoding {"wrappedValue": ....} and skip directly to the wrapped value using singleValueContainer()
This fails when CodingKeys.foo does not exist within the container so we should use decodeIfPresent() instead.
While we cannot change the synthesised code at all we can add a specialised extension to KeyedDecodingContainer that the synthesised code will call instead.
I like that solution thank you! So that essentially means I have to have an extension on the KeyedDecodingContainer for every propertyWrapper that I want to work with Codable correct?