Swift Decodable-如何避免泛型?

问题描述

我正在从JSON REST API中检索复杂的嵌套对象。

DocumentDraft
 - uuid: String
 - schema: Schema // Very complicated object with many variations
 - url: String
 - values: [Value]
 - successors: [String]
 - predecessors: [String]

Value
 - key: String
 - val: String? OR [String]?   // <-- This is the problem

我认为解决此问题的正确方法是引入泛型。

struct Value<V: Decodable>: Decodable {
  let key: String
  let val: V?
}

...但是,即使如此,values还是一个混合数组,所以我看不到声明V是有帮助的。

但是,然后,当然,泛型类型会沿层次结构一直传播到DocumentDraft对象,发布者,我的API调用等。这污染了否则非常干净易读的调用的整个链和对象。我只想在Value级别上处理此问题,然后让JSONDecoder简单地以某种方式返回两者之一。

是否有另一种方式可以处理可选val作为String[String]的两种可能性,而无需更改整个父对象?

解决方法

您可以仅使用[String]类型并手动实现init(from:)协议的Decodable功能,如下所示:

struct Value: Decodable {
    let key: String
    let val: [String]?
    
    enum CodingKeys: String,CodingKey {
        case key,val
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        key = try container.decode(String.self,forKey: .key)
        do {
            if let string = try container.decodeIfPresent(String.self,forKey: .val) {
                val = [string]
            } else {
                val = nil
            }
        } catch DecodingError.typeMismatch {
            val = try container.decodeIfPresent([String].self,forKey: .val)
        }
    }
}

成功解码为String值时,请创建仅包含一个元素的字符串数组。解码为String值失败时,请尝试解码为[String]