[英]Decoding a generic type in Argo
我正在使用Thoughtbot的Argo框架将JSON对象解析为模型。
我遇到了一个问题,我有一个协议及其扩展,如此
protocol SomeProtocol {
associatedtype Model
func foo()
}
extension SomeProtocol where Model: Decodable {
func foo() -> Model? {
// someJSON is AnyObject in this case, say, from a network call
guard let model: Model = decode(someJSON) else { return nil }
return model
}
}
并且符合此协议的类看起来像这样
class SomeClass: SomeProtocol {
typealias Model = ArgoModel
func bar() {
print(foo())
}
}
和这样的模型
struct ArgoModel {
let id: String
}
extension ArgoModel: Decodable {
static func decode(j: AnyObject) -> Decoded<ArgoModel> {
return curry(self.init)
<^> j <| "id"
}
}
(我也在使用他们的Curry库来讨论init方法)
我遇到的问题是,在SomeProtocol扩展中,关联类型Model不能被Argo解码。 我得到的错误是
No 'decode' candidates produced the expected contextual result type 'Self.Model?'
这是Swift类型系统的限制吗? 还是有什么我想念的?
在研究了一些之后,似乎这是Swift类型系统的限制,如Swift 2.3。 问题的确切原因是诸如集合和monad之类的上下文类型不能符合Argo中的Decodable。 所以我的模型只要不包含在集合中就可以工作。 使用Swift 3.0,目标是允许
使受约束的扩展符合新协议的能力(即,Equatable元素的数组是Equatable)
如本期所述: https : //github.com/thoughtbot/Argo/issues/334
我目前的解决方法是使其中包含的车型阵列复数模型,并进行解码,在SomeProtocol扩展。 所以现在我的模型看起来像这样:
struct ArgoModels {
let models: [ArgoModel]
}
extension ArgoModels: Decodable {
static func decode(j: JSON) -> Decoded<ArgoModels> {
switch j {
case .Array(let a):
return curry(self.init) <^> sequence(a.map(ArgoModel.decode))
default:
return .typeMismatch("Array", actual: j)
}
}
}
struct ArgoModel {
let id: String
}
extension ArgoModel: Decodable {
static func decode(j: AnyObject) -> Decoded<ArgoModel> {
return curry(self.init)
<^> j <| "id"
}
}
然后在实现类中,我可以创建一个typealias,Model可以是一个对象,也可以是通用方式的集合。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.