我有点被困在这里了。我有一个结构体,其中有几个可编码为字符串的字段(下面是类似的示例):
struct MyColor {
var red: UInt8
var green: UInt8
var blue: UInt8
}
extension MyColor: Codable {
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let value = try container.decode(String.self)
self = try MyColor.from(string: value) // <- Creates MyColor from string like "#001122"
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(stringValue) // <- Converts MyColor to string like "#121212"
}
}
这工作得很好,直到我想对
[MyColor: String]
字典进行编码。默认实现生成无键数组:
["#121212", "Hello", "#112233", "Bye"]
当我想要带键的对象时:
{
"#121212": "Hello",
"#112233": "Bye"
}
我发现如果类型符合
CodingKeyRepresentable
,这是可能的,但这需要我添加一个CodingKey
,这就是我停止遵循实现它的方法的地方。
有没有一种方法可以同时存档:将多个值编码为单个字符串,并使用该字符串作为键控 json 表示的键?
SingleValueContainer
无法工作,因为 – 顾名思义 – 它处理字典的 value,而不是键。
实施
CodingKeyRepresentable
并不难。您需要一个辅助结构来创建 CodingKey
。这是最短的形式
struct AnyCodingKey: CodingKey {
let stringValue: String
var intValue: Int?
init?(stringValue: String) { self.stringValue = stringValue }
init?(intValue: Int) {
self.stringValue = String(intValue)
self.intValue = intValue
}
}
您还需要
MyColor
中具有签名 init(from string: String)
的 init 方法来替换静态 MyColor.from(string: String)
方法。 CodingKeyRepresentable
的实现是
extension MyColor: CodingKeyRepresentable {
var codingKey: CodingKey {
AnyCodingKey(stringValue: stringValue)!
}
init?<T>(codingKey: T) where T : CodingKey {
self.init(from: codingKey.stringValue)
}
}
如果
Codable
不代表 值,则无需遵守
MyColor