首页 > 解决方案 > 使用通用参数调用函数需要类型的无参数初始化

问题描述

我无法让使用泛型类型的函数调用使用URLSession DataTaskPublisher...

code我调用的 API 总是以 HTTP 200 响应,并通过带有指示符的字符串在 JSON 中指示它是否成功。

我创建了一个protocol所有响应对象都符合的,例如:

protocol APIResponse: Decodable {
    var code: String { get }
}

我的实际反应是这样的:

struct LoginResponse :  APIResponse {
    let code: String
    let name: String
    enum CodingKeys: String, CodingKey {
        case code = "code"
        case name = "name"
    }
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        code = try values.decode(String.self, forKey: .code)
        name = try values.decode(String.self, forKey: .name)
    }
}

现在我想要一个可以使用的函数:

    private func call<T: APIResponse>(_ endpoint: String, using data: Encodable, providing response: T)
                    -> AnyPublisher<T, Error> {
        let request = createRequest(for: endpoint, using: data)
        return session
                .dataTaskPublisher(for: request)
                .map {
                    $0.data
                }
                .decode(type: T.self, decoder: decoder)
                .tryMap {
                    response in
                    if response.code.suffix(1) != "I" {
                        throw MyError(message: "Error \(code)")
                    }
                    return response
                }
                .eraseToAnyPublisher()
    }

到目前为止,一切都很好!

但这是问题......我想这样使用它:

    func login() -> AnyPublisher<String, Error> {
        call("login", using: LoginRequest(), providing: LoginResponse)
                .map {
                    $0.name
                }
                .eraseToAnyPublisher()
    }

编译器抱怨Type 'LoginResponse.Type' cannot conform to 'APIResponse'; only struct/enum/class types can conform to protocols

我的修复(有效,但很笨拙),它提供了一个无参数init()LoginResponse这样称呼它:call("login", using: LoginRequest(), providing: LoginResponse())

有什么方法可以让 Generic 在没有 no-arg 的情况下工作init()

我应该采取完全不同的方法吗?

标签: swiftcombine

解决方案


在将参数call更改为的标题中response

...providing response: T.Type)

并使用.self

call("login", using: "request", providing: LoginResponse.self)

推荐阅读