可以同时实现Void和Codable的泛型

时间:2019-07-03 09:15:14

标签: swift

这里我有一个用于api结果的结构

struct Response<Result> {
    let status: Int
    let message: String
    let result: Result
}

现在通常使它符合Codable意味着Result对象需要为Codable。这样做看起来像是以下其中之一

struct Response<Result: Codable>: Codable {...}

// or

extension Response: Codable where Result: Codable {}

我遇到的问题是某些响应没有result键,我希望能够像使用Response类型一样使用Void对象而不是{ {1}}就像so question

目前,我有一种解决方法,可以这样声明另一个Response<Void>类型,其中没有Response变量:

result

有没有解决的办法,这样就不必声明另一种struct BaseResponse { let status: Int let message: String } 类型了?


我尝试执行以下操作,但没有任何作用

  1. 我无法使Response符合Void
  2. Codable
  3. 处具有对codable的另一种扩展一致性
Result: Void
  1. extension Response: Codable where Result: Codable {} extension Response: Codable where Result: Void {} 也不起作用,因为它没有它自己的初始化程序,因此我无法使其符合Never
  2. 像这样创建符合Codable的{​​{1}}类型
Nothing

所以我可以使用这样的响应

Codable

但是问题是我无法使用struct Nothing: Codable, Hashable { init() {} static var nothing: Nothing { return .init() } } 类型专用的let response: Response<Nothing> = Response( status: 200, message: "Success", result: .nothing ) or public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.status = try container.decode(forKey: .status) self.message = try container.decode(forKey: .message) // These lines don't work. if let result = try container.decodeIfPresent(Result.self, forKey: .result) { self.result = result } else { self = .nothing } } 方法。这么多。

2 个答案:

答案 0 :(得分:1)

result设为optional,键入 Result? 。现在,当响应包含针对result键的值时,它将在result属性中进行设置。否则,如果没有nil键,它将保留为result

struct Response<Result: Codable>: Codable {
    let status: Int
    let message: String
    let result: Result? //here....
}

解析这样的数据,

do {
    let response = try JSONDecoder().decode(Response<String>.self, from: data)
    print(response)
} catch {
    print(error)
}

根据需要使用Response<String>中想要的任何类型。

示例:

  1. 如果 JSON {"status":1,"message":"This is a message","result":"QWERTY"}

然后responseResponse<String>(status: 1, message: "This is a message", result: Optional("QWERTY"))

  1. 如果 JSON {"status":1,"message":"This is a message"}

然后responseResponse<String>(status: 1, message: "This is a message", result: nil))

答案 1 :(得分:1)

您可以这样定义init(from:)方法:

init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)

    status = try container.decode(Int.self, forKey: .status)
    message = try container.decode(String.self, forKey: .message)

    if Result.self is Nothing.Type {
        result = Nothing() as! Result
    } else {
        result = try container.decode(Result.self, forKey: .result)
    }
}

您检测到自己处于Response<Nothing>情况,并完全跳过对结果的解码。这样,在需要结果的情况下,您可以保持常规的result解码,并且可以使其保持非可选状态。