I've got a struct with a Double property that is represented as a String in the JSON coming from the backend.
struct Test: Codable {
@StringRepresentation
var value: Double?
}
Instead of implement init(from:) I've created the following property wrapper that takes advantage of LosslessStringConvertible to convert to and from String
@propertyWrapper
struct StringRepresentation<T: LosslessStringConvertible> {
private var value: T?
var wrappedValue: T? {
get {
return value
}
set {
value = newValue
}
}
}
extension StringRepresentation: Codable {
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if container.decodeNil() {
value = nil
} else {
let string = try container.decode(String.self)
value = T(string)
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
if let value = value {
try container.encode("\(value)")
} else {
try container.encodeNil()
}
}
}
This works for
{
"value": "12.0"
}
and
{
"value": null
}
but fails when the property is missing
{
}
giving the error
▿ DecodingError
▿ keyNotFound : 2 elements
- .0 : CodingKeys(stringValue: "value", intValue: nil)
▿ .1 : Context
- codingPath : 0 elements
- debugDescription : "No value associated with key CodingKeys(stringValue: \"value\", intValue: nil) (\"value\")."
- underlyingError : nil
I'm guessing this happens because the underlying StringRepresentation is not Optional.
How can I make it optional?
Edit: Also, I have to encode the object as
{
"value": null
}
i.e the value can't be omitted.