【问题标题】:Decoding a generic type in Argo在 Argo 中解码泛型类型
【发布时间】:2016-04-28 17:08:32
【问题描述】:

我正在使用 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 库来 curry init 方法)

我遇到的问题是,在 SomeProtocol 扩展中,关联类型 Model 无法被 Argo 解码。我得到的错误是

No 'decode' candidates produced the expected contextual result type 'Self.Model?'

这是 Swift 类型系统的限制吗?还是我缺少什么?

【问题讨论】:

    标签: ios swift generics protocols


    【解决方案1】:

    经过更多研究,这似乎是 Swift 2.3 中 Swift 类型系统的限制。问题的确切原因是集合和 monad 等上下文类型不符合 Argo 中的 Decodable。所以我的模型只要不包含在集合中就可以工作。使用 Swift 3.0,目标是允许

    使受约束的扩展符合新协议的能力(即,Equatable 元素的数组是 Equatable)

    如本期所示:https://github.com/thoughtbot/Argo/issues/334

    我目前的解决方法是制作一个复数模型,其中包含模型数组并在 SomeProtocol 扩展中解码 that。所以现在我的模型看起来像这样:

    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"
        }
    }
    

    然后在实现类中,我可以创建一个类型别名 Model,它可以是单个对象,也可以是它们的集合。

    【讨论】:

      猜你喜欢
      • 2021-10-22
      • 1970-01-01
      • 1970-01-01
      • 2021-08-11
      • 2021-12-01
      • 2021-09-21
      • 1970-01-01
      • 2018-10-05
      • 1970-01-01
      相关资源
      最近更新 更多