简体   繁体   中英

How to implement to a generic protocol, which has a function using the Type of associatedtype?

I am creating some class confirms to a generic protocol, this generic protocol has a method which accept a parameter of the Type of the associatedtype , I use Xcode to generate the stub for me:


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

Instead of ResponseObject.Type it generates ResponseObject.Protocol for me, I don't actually know what this ResponseObject.Protocol is, and I can not pass SomeObject.self as the parameter like this:

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

compiler gave me this error:

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

I think something wrong with my implementation, anyone can give me any ideas?

Thanks!

This isn't how associated types work. get should be generic over its response type, but the network manager itself isn't generic over some specific response type. I believe what you meant to here is this:

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

For a more worked-out version of this specific problem you can read my protocol series , but the important concept here is that NetworkManager doesn't vary over its ResponseType, so there's no reason to make its ResponseType an associated type.

What you wrote is trying to say "some network managers will have a Codable ResponseType, and other network managers will have some other kind of ResponseType." Not "some other specific response type (like User)" but "some other protocol that its response types would have to conform to." While it's conceivable to build something like that, it's much more complex, and you'd need to explain your precise use case in order to design it. Specifically, you'd need to show several concrete implementations of your protocol in order to see what kind of shared code you're trying to extract.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM