CodingKeyRepresentable for singleValueContainer

问题描述 投票:0回答:1

我有点被困在这里了。我有一个结构体,其中有几个可编码为字符串的字段(下面是类似的示例):

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 表示的键?

ios swift dictionary codable
1个回答
1
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.