Swift: 模板定义中的常量

Swift: Constant in Template Definition

我正在与喜欢将 json 主体封装在另一个对象(例如数据)中的后端开发人员合作:

示例:

GET: /user/current:

{
  data: {
          firstName: "Evan",
          lastName: "Stoddard"
        }
}

我只想对响应调用 json 解码以获取我创建的用户结构,但添加的数据对象需要另一个结构。为了解决这个问题,我创建了一个通用模板 class:

struct DecodableData<DecodableType:Decodable>:Decodable {

    var data:DecodableType

}

现在我可以获取我的 json 负载,如果我想获取用户结构,只需获取我的模板的数据 属性:

let user = JSONDecoder().decode(DecodableData<User>.self, from: jsonData).data

这一切都很好,但有时,关键 data 并不总是 data

我觉得这很可能是相当微不足道的事情,但有没有一种方法可以在我的模板定义中添加一个参数,这样我就可以更改枚举编码键,因为该数据键可能会改变?

类似下面的内容?

struct DecodableData<DecodableType:Decodable, Key:String>:Decodable {

    enum CodingKeys: String, CodingKey {
        case data = Key
    }

    var data:DecodableType

}

这样我就可以传入目标可解码 class 以及封装该对象的密钥。

试试这样的东西:

struct GenericCodingKey: CodingKey {
    var stringValue: String

    init(value: String) {
        self.stringValue = value
    }

    init?(stringValue: String) {
        self.stringValue = stringValue
    }

    var intValue: Int?

    init?(intValue: Int) {
        return nil
    }
}

struct DecodableData<DecodableType: CustomDecodable>: Decodable {

    var data: DecodableType

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: GenericCodingKey.self)
        data = try container.decode(DecodableType.self, forKey: GenericCodingKey(value: DecodableType.dataKey))
    }
}

protocol CustomDecodable: Decodable {
    static var dataKey: String { get }
}

extension CustomDecodable {
    static var dataKey: String {
        return "data" // This is your default
    }
}


struct CustomDataKeyStruct: CustomDecodable {
    static var dataKey: String = "different"
}

struct NormalDataKeyStruct: CustomDecodable {
    //Change Nothing
}

无需编码键。相反,您需要一个简单的容器来将 JSON 解析为具有一对 key-value 的字典,并丢弃密钥。

struct Container<T>: Decodable where T: Decodable {
    let value: T

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        let dict = try container.decode([String: T].self)

        guard dict.count == 1 else {
            throw DecodingError.dataCorruptedError(in: container, debugDescription: "expected exactly 1 key value pair, got \(dict.count)")
        }

        value = dict.first!.value
    }
}

如果 JSON 为空或有多个 key-value 对,则会引发异常。

假设一个简单的结构,例如

struct Foo: Decodable, Equatable {
    let a: Int
}

不管key如何都可以解析:

let foo1 = try! JSONDecoder().decode(
    Container<Foo>.self,
    from: #"{ "data": { "a": 1 } }"#.data(using: .utf8)!
).value

let foo2 = try! JSONDecoder().decode(
    Container<Foo>.self,
    from: #"{ "doesn't matter at all": { "a": 1 } }"#.data(using: .utf8)!
).value

foo1 == foo2 // true

这也适用于以 null 作为值的 JSON 响应,在这种情况下,您需要将其解析为您的类型的可选项:

let foo = try! JSONDecoder().decode(
    Container<Foo?>.self,
    from: #"{ "data": null }"#.data(using: .utf8)!
).value // nil