I want to encode instances of the existing NWInterface
class which has a type
field of type NWInterface.InterfaceType
which is an enum
.
Is there a way to easily add the Encodable
interface to that nested type? At the moment my workaround is to handle the encoding in an extension to the enclosing class:
extension NWInterface : Encodable {
enum CodingKeys: CodingKey {
case name
case type
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
switch type {
case .wifi:
try container.encode("wifi", forKey: .type)
case .cellular:
try container.encode("cellular", forKey: .type)
case .wiredEthernet:
try container.encode("ethernet", forKey: .type)
case .loopback:
try container.encode("loopback", forKey: .type)
case .other:
try container.encode("other", forKey: .type)
default:
try container.encode("unknown", forKey: .type)
}
}
}
This feels unsatisfactory, especially since for my own defined enum
types I can simply add the Encodable
interface at the point of definition and get the implementation "for free".
Can you add a Encodable
conformance to a nested enum?
Yes
Do you get it for free, like with your own enums?
No. I don't know why, but automatic Codable
synthesis seems to require that the extension be in the same file as the struct
, class
or enum
.
Here's what the implementation extending the nested enum
would look like.
extension NWInterface : Encodable {
enum CodingKeys : CodingKey {
case name, type
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
try container.encode(type, forKey: .type)
}
}
extension NWInterface.InterfaceType : Encodable {
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .wifi:
try container.encode("wifi")
case .cellular:
try container.encode("cellular")
case .wiredEthernet:
try container.encode("ethernet")
case .loopback:
try container.encode("loopback")
case .other:
try container.encode("other")
default:
try container.encode("unknown")
}
}
}
You could also squeeze the second extension down to:
extension NWInterface.InterfaceType : Encodable {
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode("\(self)")
}
}
provided you take appropriate measures to handle unexpected strings in your Decoder
.