I have a class that I want to custom encode into JSON:
class Declination: Decodable, Encodable {
var asString: String
var asDouble: Double
init(_ asString: String) {
self.asString = asString
self.asDouble = raToDouble(asString)
}
required init(from decoder: Decoder) throws {
let value = try decoder.singleValueContainer()
self.asString = try value.decode(String.self)
self.asDouble = declinationToDouble(asString)
}
}
As you can see, I calculate the double form of the declination when I decode a JSON file containing the data. What I want to do now is ENCODE the class back out as a single string.
Currently the standard JSON encode in Swift produces the following:
"declination":{"asDouble":18.26388888888889,"asString":"+18:15:50.00"}
what I want to produce is:
declination:"+18:15:50.00"
How can I easily do that? I've read up about custom encoders and such, and I get confused about the containers and what keys are being used. I think there might be a simple answer where I could just code:
extension Coordinate: Encodable {
func encode(to encoder: Encoder) throws {
return encoder.encode(self.asString)
}
}
But experienced Swift developers will immediately see that won't work. Should I do JSONSerialization instead? Can I just write a toString() extension and have JSON pick that up?
Any help would be appreciated.
Thanks, Robert
You are close. The custom encode(to:)
just needs to be the inverse operation of init(from:)
(using a single value container) like this:
func encode(to encoder: Encoder) throws {
var c = encoder.singleValueContainer()
try c.encode(asString)
}
Should I do JSONSerialization instead?
Nope! That’s a huge step backwards from the nice Swift Codable
API.
BTW, would it be feasible to make asDouble
be a computed property, derived from asString
as needed? Or the other way around? Ideally only one of them would be a stored property to serve as the single source of truth.