2016-04-28 76 views
4

我正在使用Thoughtbot的Argo框架將JSON對象解析爲模型。在Argo中解碼泛型類型

我遇到了一個問題,我有一個協議及其擴展,像這樣

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

(我也在用他們的咖喱庫以及咖喱ini t方法)

我遇到的問題是,在SomeProtocol擴展中,Argo無法解碼associatedtype,Model。我得到的錯誤是

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

這是Swift類型系統的限制嗎?還是有我失蹤的東西?

回答

1

經過一番研究,似乎這是Swift 2.3 Swift類型系統的限制。問題的確切原因是集合和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,型號,它們可以是單個對象或它們的一種通用方式的集合。