1

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 ?

3
  • 1
    Are you implementing a separate encode(to:) method that is not shown? Because the generated Encodable conformance is not going to call your encode(to:type:) method. Commented Oct 17, 2022 at 15:12
  • No, I will just call: lookUpObj.encode(to:type:) when I encode the object lookupObj Commented Oct 17, 2022 at 15:15
  • 2
    Well, that works too :) In that case you don't actually need to conform to Encodable, and I would argue that you should not. Commented Oct 17, 2022 at 15:18

1 Answer 1

3

You can create a common protocol for both of your enums, add the enum cases you need as static vars, 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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.