ios singleValueContainer的CodingKeyRepresentable

iibxawm4  于 2023-08-08  发布在  iOS
关注(0)|答案(1)|浏览(102)

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

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

qyyhg6bp

qyyhg6bp1#

SingleValueContainer不能工作,因为顾名思义,它处理的是字典的,而不是键。
实现CodingKeyRepresentable并不难。您需要一个helper结构来创建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)
    }
}


如果MyColor不代表,则不需要符合Codable

相关问题