I'm struggling to write a single function that encodes the following struct:
struct Lookup: Encodable {
var id: Int
var name: String
enum StateCodingKeys: String, CodingKey {
case id = "stateId"
case name = "stateName"
}
enum CityCodingKeys: String, CodingKey {
case id = "cityId"
case name = "cityName"
}
func encode(to encoder: Encoder, type: StateCodingKeys.Type) throws {
var container = encoder.container(keyedBy: type)
try container.encode(id, forKey: .id)
try container.encode(name, forKey: .name)
}
}
the custom encode
function here takes StateCodingKeys.Type
as a parameter, but I can't find a way to let this function accept any CodingKey
type, like the CityCodingKeys
enum, is there a way to do that ?
You can create a common protocol for both of your enums, add the enum cases you need as static var
s, and conform the enums to the protocol.
protocol LookupCodingKey: CodingKey {
static var id: Self { get }
static var name: Self { get }
}
enum StateCodingKeys: String, LookupCodingKey {
case id = "stateId"
case name = "stateName"
}
enum CityCodingKeys: String, LookupCodingKey {
case id = "cityId"
case name = "cityName"
}
Then you can add the protocol as a generic constraint:
func encode<CodingKeyType: LookupCodingKey>(to encoder: Encoder, type: CodingKeyType.Type) throws {
var container = encoder.container(keyedBy: type)
try container.encode(id, forKey: .id)
try container.encode(name, forKey: .name)
}
Side note:
If you just want to call encode(to:type:)
directly to encode a Lookup
, I would suggest that you do not conform to Encodable
, since Lookup
would have a generated encode(to:)
method, that does not call your encode(to:type:)
.
When you accidentally pass Lookup
to something that expects an Encodable
, and that something encodes it using encode(to:)
, it will have the unexpected keys id
and name
.
I haven't tried, but you might be able to conform to EncodableWithConfiguration
instead, with the configuration being the type of the coding key.