如何解决解码通用可解码类型
我需要创建一个通用结构,该结构将容纳从网络返回的任何可解码类型,因此我创建了以下内容:
struct NetworkResponse<Wrapped: Decodable>: Decodable {
var result: Wrapped
}
所以我可以使用像这样的解码方法:
struct MyModel: Decodable {
var id: Int
var name: String
var details: String
}
func getData<R: Decodable>(url: URL) -> AnyPublisher<R,Error>
URLSession.shared
.dataTaskPublisher(for: url)
.map(\.data)
.decode(type: NetworkResponse<R>.self,decoder: decoder)
.map(\.result)
.eraseToAnyPublisher()
//call site
let url = URL(string: "https://my/Api/Url")!
let models: [MyModel] = getData(url: url)
.sink {
//handle value here
}
但是,我注意到网络中的某些响应包含了result
键,而另一些则没有:
结果:
{
"result": { [ "id": 2,"name": "some name","details": "some details"] }
}
无结果:
[ "id": 2,"details": "some details" ]
这会导致.map(\.result)
发布者出现以下错误,因为它在返回的json中找不到result
键:
(typeMismatch(Swift.Dictionary<Swift.String,Any>,Swift.DecodingError.Context(codingPath: [],debugDescription: "Expected to decode Dictionary<String,Any> but found an array instead.",underlyingError: nil)))
如何在NetworkResponse
结构中处理任何一种情况,以免发生此类错误?
解决方法
您发布的JSON无效,但我认为这是一个错字,实际上是:
{ "id": 2,"name": "some name","details": "some details" }
// or
{ "result": { "id": 2,"details": "some details" } }
({
}
而不是[
]
)
也许最干净的是使用手动解码器,如果第一种失败,它可以退回到另一种类型:
struct NetworkResponse<Wrapped> {
let result: Wrapped
}
extension NetworkResponse: Decodable where Wrapped: Decodable {
private struct ResultResponse: Decodable {
let result: Wrapped
}
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
do {
let result = try container.decode(ResultResponse.self)
self.result = result.result
} catch DecodingError.keyNotFound,DecodingError.typeMismatch {
self.result = try container.decode(Wrapped.self)
}
}
}
或者,您可以回退到Combine。我本来不会采用这种方法,但出于完整性考虑:
URLSession.shared
.dataTaskPublisher(for: url)
.map(\.data)
.flatMap { data in
Just(data)
.decode(type: NetworkResponse<R>.self,decoder: decoder)
.map(\.result)
.catch { _ in
Just(data)
.decode(type: R.self,decoder: decoder)
}
}
.eraseToAnyPublisher()
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。