【问题标题】:Swift JSONEncoder encoding generic type with custom structureSwift JSONEncoder 使用自定义结构编码泛型类型
【发布时间】:2020-08-15 22:33:43
【问题描述】:

我目前正在尝试编码一个通用结构 (T),它具有 JSONEncoder 的此类属性:

struct A <T:Codable> : Codable {
    var id: Int
    var attribute : T
    
    init(id: Int, attribute: T){
        self.id = id
        self.attribute = attribute
    }
    
}

struct B : Codable {
    var name: String
    var age: Int
}
let encoder = JSONEncoder()
let foo = A<B>(id: 1, attribute: B(name: "name", age: 29))

try? encoder.encode(foo)

这会产生这样的 JSON:

{
  "id" : 1,
  "attribute" : {
    "name" : "name",
    "age" : 29
  }
}

但我想自定义编码以将嵌套属性获取到根级别:

{
  "id" : 1,
  "name" : "name",
  "age" : 29
}

使用自定义 CodingKey 结构对我不起作用,因为 T 可能有任意数量的属性,并且事先不知道键(属性名称)。

【问题讨论】:

    标签: json swift generics encoding


    【解决方案1】:

    这需要手动完成,通过实现encode(to:)init(from:)

    struct A <T:Codable> {
        var id: Int
        var attribute : T
    }
    
    extension A: Codable {
        enum CodingKeys: CodingKey { case id }
    
        func encode(to encoder: Encoder) throws {
           // use attribute's own encode(to:)
           try attribute.encode(to: encoder) 
    
           // then encode the id
           var container = encoder.container(keyedBy: CodingKeys.self)
           try container.encode(id, forKey: .id)
        }
    
        init(from decoder: Decoder) throws {
            // use attribute's own init(from:)
            self.attribute = try T.init(from: decoder)
            
            // decode the id
            let container = try decoder.container(keyedBy: CodingKeys.self)
            self.id = try container.decode(Int.self, forKey: .id)
        }
    }
    

    注意,这是一个非常脆弱的解决方案。我不建议按照您计划的方式对其进行编码。

    如果T 的编码容器与A 的不同(这是一个键控容器),它在运行时很容易中断,并出现错误:EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) p>

    例如,以下在运行时失败:

    let a = A(id: 1, attribute: "A")
    let data = JSONEncoder().encode(a)
    

    这是因为当TString 时,它的容器是SingleValueEncodingContainer。如果T 是一个数组,也会发生同样的情况:

    let a = A(id: 1, attribute: ["A"])
    

    因为数组是用UnkeyedEncodingContainer编码的

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-01-11
      • 2019-12-28
      • 1970-01-01
      • 2018-11-13
      • 1970-01-01
      • 1970-01-01
      • 2016-08-04
      相关资源
      最近更新 更多