如何使用具有关联类型的类型的功能实现通用协议?

时间:2019-05-30 10:39:31

标签: ios swift generics

我正在创建用于通用协议的类确认,该通用协议具有接受associatedtype类型参数的方法,我使用Xcode为我生成存根:


import UIKit

struct SomeObject: Codable {
    var id: String?
    var name: String?
}

protocol INetworkManager {
    associatedtype ResponseObject
    func get(url: String, ofType: ResponseObject.Type, completion: (ResponseObject?, Error?) -> Void)
}

class NetworkManager: INetworkManager {
    typealias ResponseObject = Codable

    func get(url: String, ofType: ResponseObject.Protocol, completion: (ResponseObject?, Error?) -> Void) {
        completion(SomeObject(id: "1", name: "hello"), nil)
    }
}

我不是ResponseObject.Type而是为我生成ResponseObject.Protocol,实际上我不知道这个ResponseObject.Protocol是什么,并且我不能像这样传递参数SomeObject.self

let networkManager = NetworkManager()
networkManager.get(url: "http://whatever.com", ofType: SomeObject.self) { (responseObject, error) in
    print("got response object named: \(responseObject.name)")
}

编译器给我这个错误:

error: Cannot convert value of type 'SomeObject.Type' to expected argument type 'NetworkManager.ResponseObject.Protocol' (aka '(Decodable & Encodable).Protocol')

我认为我的实现存在问题,任何人都可以给我提出任何想法?

谢谢!

1 个答案:

答案 0 :(得分:0)

这不是关联类型的工作方式。 get应该在响应类型上是通用的,但是网络管理器本身在某些特定响应类型上不是通用的。我相信您的意思是这样的:

protocol NetworkManager {
    func get<ResponseObject>(url: String, 
                             ofType: ResponseObject.Type, 
                             completion: (Result<ResponseObject, Error>) -> Void) 
    where ResponseObject: Decodable
}

class TrivialNetworkManager: NetworkManager {
    func get<ResponseObject>(url: String, 
                             ofType: ResponseObject.Type, 
                             completion: (Result<ResponseObject, Error>) -> Void) 
    where ResponseObject: Decodable {
        completion(.success(SomeObject(id: "1", name: "hello"))
    }
}

有关此特定问题的更详尽的版本,您可以阅读我的protocol series,但此处的重要概念是NetworkManager的ResponseType不变,因此没有理由将其ResponseType关联类型。

您写的是想说:“某些网络管理器将具有可编码的ResponseType,而其他网络管理器将具有其他类型的ResponseType。”不是“某些其他特定的响应类型(如用户)”,而是“其响应类型必须符合的其他协议”。尽管可以想到构建类似的东西,但它要复杂得多,并且您需要解释精确的用例才能进行设计。具体来说,您需要显示协议的几种具体实现,以查看要提取的共享代码类型。