使用 Swift 4 的 Decodable 解码 Void
Posted
技术标签:
【中文标题】使用 Swift 4 的 Decodable 解码 Void【英文标题】:Decoding Void with Swift 4’s Decodable 【发布时间】: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<Void>
。编译器对此不满意:
Type 'Void' does not conform to protocol 'Decodable'
编译器很快发现了我通过将Decodable
一致性添加到Void
来解决这个问题的恶作剧:
extension Void: Decodable … // Error: Non-nominal type 'Void' cannot be extended
让请求泛型而不是返回类型感觉是正确的。有没有办法让它与Void
返回类型一起工作? (例如,只是在服务器上创建一些东西而不返回任何东西的请求。)
【问题讨论】:
也许我误解了这个问题,但这取决于你 - 开发者 - 来处理 avoidingVoid
请求跨度>
我能理解你的观点,但同时感觉如果一个事物在 x 上是通用的,那么 Void
又名零元组 ()
应该是 x 的有效值。毕竟Equatable
和Decodable
是微不足道的。
@zoul 仍然想知道Request<Void>
应该是什么意思。你为什么要使用这样的东西?如果那是响应类型,则永远不会是 Void
。它可以是空的,但绝不是Void
。
empty 和Void
有什么区别?对我来说,在普通函数中有一个完美的类比,返回 Void
的请求与返回 Void
的函数相同。两者都只用于副作用。
【参考方案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
将Void
与Decodable
保持一致是不可能的。 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)
以上是关于使用 Swift 4 的 Decodable 解码 Void的主要内容,如果未能解决你的问题,请参考以下文章
Swift 4 JSON Decodable 解码类型更改的最简单方法
使用 Swift 4 Decodable 将字符串 JSON 响应转换为布尔值
Swift 4 Decodable - 没有与键 CodingKeys 关联的值 [重复]