【问题标题】:Decoding Void with Swift 4’s Decodable使用 Swift 4 的 Decodable 解码 Void
【发布时间】:2018-01-19 23:03:20
【问题描述】:

我有一个通用的 REST 请求:

struct Request<T> {…}

T是请求的返回类型,例如:

struct Animal {…}
let animalRequest = Request<Animal>
let animal: Animal = sendRequest(animalRequest)

现在我想说泛型类型必须符合Decodable,这样我才能解码来自服务器的 JSON 响应:

struct Request<T> where T: Decodable {…}
struct Animal: Decodable {…}

这是有道理且有效的——直到我收到一个没有响应的请求,Request&lt;Void&gt;。编译器对此不满意:

Type 'Void' does not conform to protocol 'Decodable'

编译器很快发现了我通过将Decodable 一致性添加到Void 来解决这个问题的恶作剧:

extension Void: Decodable {…} // Error: Non-nominal type 'Void' cannot be extended

让请求泛型而不是返回类型感觉是正确的。有没有办法让它与Void 返回类型一起工作? (例如,只是在服务器上创建一些东西而不返回任何东西的请求。)

【问题讨论】:

  • 也许我误解了这个问题,但这取决于你 - 开发者 - 来处理 avoiding Void 请求跨度>
  • 我能理解你的观点,但同时感觉如果一个事物在 x 上是通用的,那么 Void 又名零元组 ()应该是 x 的有效值。毕竟EquatableDecodable 是微不足道的。
  • @zoul 仍然想知道Request&lt;Void&gt; 应该是什么意思。你为什么要使用这样的东西?如果那是响应类型,则永远不会是 Void。它可以是空的,但绝不是Void
  • empty 和Void 有什么区别?对我来说,在普通函数中有一个完美的类比,返回 Void 的请求与返回 Void 的函数相同。两者都只用于副作用。

标签: json swift decodable


【解决方案1】:

我发现有时其他类型的其他编码对象可以解码为 NoReply.self。例如自定义错误类型(枚举)即可。

本案例的游乐场示例:

enum MyError: String, Codable {
    case general
}

let voidInstance = VoidResult()
let errorInstance = MyError.general
let data1 = try! JSONEncoder().encode(voidInstance)
let data2 = try! JSONEncoder().encode(errorInstance)

let voidInstanceDecoded = try! JSONDecoder().decode(VoidResult.self, from: data1)
//VoidResult as expected

let errorInstanceDecoded = try! JSONDecoder().decode(MyError.self, from: data2)
//MyError.general as expected

let voidInstanceDecodedFromError = try! JSONDecoder().decode(VoidResult.self, from: data2)
//VoidResult - NOT EXPECTED

let errorInstanceDecodedFromVoid = try! JSONDecoder().decode(ScreenError.self, from: data1)
//DecodingError.typeMismatch - Expected

所以我的建议是添加“NoReply 的唯一性(zoul 的回答)):

struct VoidResult: Codable {
    var id = UUID()
}

let voidInstanceDecodedFromError = try! JSONDecoder().decode(VoidResult.self, from: data2)
//DecodingError.typeMismatch - Now its fine - as expected

【讨论】:

    【解决方案2】:

    一个简单的解决方法是引入一个自定义的“no-reply”类型来替换Void

    struct NoReply: Decodable {}
    

    VoidDecodable 保持一致是不可能的。 Void 只是空元组() 的类型别名,元组目前不能符合协议,但它们最终会。

    【讨论】:

    • 这个解决方案很好
    • 太棒了。谢谢!
    • 这对我不起作用,我得到一个 DecodingError.dataCorrupted with context: Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "No value." UserInfo={NSDebugDescription=No value.}))
    • @Marmoy 也许您正试图解码一个空数据。 JSONDecoder 要求输入数据是有效的 JSON 文档。作为一种解决方法,您可以检测响应数据是否为空,在这种情况下,将其替换为模拟的空 json 数据:let emptyJson = "{}".data(using: .utf8)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-21
    • 2019-03-13
    • 2018-04-10
    • 2018-07-08
    • 1970-01-01
    • 1970-01-01
    • 2017-11-19
    相关资源
    最近更新 更多