I want to make a dictionary from a encodable struct with a default implementation property.
struct MyStruct: MyStructProtocol {
var value: String
}
The struct implements a protocol. That protocol has two variables. One variable has a default implementation.
protocol MyStructProtocol: Encodable {
var defaultValue: String { get }
var value: String { set get }
}
extension MyStructProtocol {
var defaultValue: String { return "my-default-value" }
}
To that I use that Encodable
Extension from How can I use Swift’s Codable to encode into a dictionary?:
extension Encodable {
var asDictionary: [String: Any]? {
guard let data = try? JSONEncoder().encode(self) else { return nil }
return (try? JSONSerialization.jsonObject(with: data, options: .allowFragments)).flatMap { $0 as? [String: Any] }
}
}
So when I instantiate the struct and "encode" it to a dictionary:
let myStruct = MyStruct(value: "my-value")
let myStructDictionary = myStruct.asDictionary
then the defaultValue
is not included:
["value": "my-value"]
But what I need is (included the defaultValue):
["defaultValue": "my-default-value", "value": "my-value"]
The synthesized encoder considers only the members in the struct, not any properties in a protocol extension nor computed properties.
You have to write a custom initializer. And I'd prefer to make the struct adopt Encodable
rather than the protocol.
struct MyStruct: MyStructProtocol, Encodable {
var value: String
private enum CodingKeys: String, CodingKey { case value, defaultValue }
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(value, forKey: .value)
try container.encode(defaultValue, forKey: .defaultValue)
}
}
protocol MyStructProtocol { ...