Generi c Кодируемый не может быть выведен - PullRequest
0 голосов
/ 01 марта 2020

У меня есть класс API со следующей функцией:

static func JSONPostRequest<EncodableType:Codable, DecodableType:Codable>(endpoint: String, jsonData: EncodableType, callback: @escaping (DecodableType) -> Void, clientErrorCallback: @escaping (Error) -> Void, responseErrorCallback: @escaping (URLResponse) -> Void, requestHeaders: [String: String]?) {

    // Encoding the data into JSON
    var jsonData: Data = Data();
    do {
        jsonData = try JSONEncoder().encode(jsonData)
    }
    catch {
        print("JSON Encode")
        return ;
    }

    // Setup the request
    var request: URLRequest = URLRequest(url: URL(string: self.endpoint + self.apiVersion + "/" + endpoint)!)
    request.httpMethod = "POST"
    request.httpBody = jsonData

    // Set the custom headers
    if(requestHeaders != nil) {
        for (headerKey, headerValue) in requestHeaders! {
            request.setValue(headerValue, forHTTPHeaderField: headerKey)
        }
    }

    let task = URLSession.shared.dataTask(with: request) { (data, response, error) in

        // Was there an error in request?
        if error != nil {
            clientErrorCallback(error!)
            return
        }

        // Response code is 2XX?
        guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else {
            responseErrorCallback(response!)
            return
        }

        // Has mime type fine?
        guard let mime = response!.mimeType, mime == "application/json" else {
            print("Wrong MIME type!")
            return
        }

        let decoder = JSONDecoder()
        let loginResponse = try! decoder.decode(DecodableType.self, from: data!)

        callback(loginResponse)
    }

    task.resume()
}

Но когда я хотел бы вызвать его из моего вида входа в систему ...:

API.JSONPostRequest(
        endpoint: "login",
        jsonData: LoginRequest(username: self.username, password: self.password),
        callback: { loginResponse in
            // success callback

            if loginResponse.success && loginResponse.token != "" {
                callback(loginResponse)
            }
            else {
                // backend logic error
            }
        }, clientErrorCallback: { error in
            // client error
        }, responseErrorCallback: { urlResponse in
            // response error
        }, requestHeaders: headers
    )

... Я получаю следующее сообщение об ошибке:

Generic parameter 'EncodableType' could not be inferred

Вот моя реализация LoginRequest:

struct LoginRequest: Codable {
var username: String;
var password: String;

}

Сообщение об ошибке отображается рядом с первой строкой вызова функции, рядом с "API.JSONPostRequest (".

В чем здесь проблема?

1 Ответ

1 голос
/ 01 марта 2020

Вы не указали тип для loginResponse, и из этого кода невозможно угадать, что это такое. Глядя на код, который вы разместили, я не могу понять, каким должен быть ответ (ничто из того, что вы здесь разместили, не имеет значения .success или .token).

Я полагаю, вы подразумевается добавить следующий код:

struct LoginResponse: Codable {
    var success: Bool
    var token: String
}

И я предполагаю, что где-то есть переменная callback типа (LoginResponse) -> Void.

С этим типом вам все равно нужно разрешить компилятор знает, что это то, что вы ожидаете. У него нет возможности угадать бесконечное число типов, которые могут быть возвращены. Вам нужно LoginResponse:

        ...
        callback: { (loginResponse: LoginResponse) in
        ...

Альтернативно, вы можете настроить сигнатуру типа так, чтобы она передавала ожидаемый тип, например:

static func JSONPostRequest<Request, Response>(endpoint: String,
                                               jsonData: Request,
                                               returning: Response.Type = Response.self,
                                               callback: @escaping (Response) -> Void,
                                               clientErrorCallback: @escaping (Error) -> Void,
                                               responseErrorCallback: @escaping (URLResponse) -> Void,
                                               requestHeaders: [String: String]?)
    where Request: Encodable, Response: Decodable {

Это позволит вам передать returning: LoginResponse.self, что может быть приятнее, чем встроить его в замыкание:

        ...
        returning: LoginResponse.self,
        callback: { loginResponse in
        ...

(Тем не менее, то, что я здесь обсуждаю, исправляет тот факт, что DecodableType на самом деле является неоднозначным. Тот факт, что вы получаете ошибку на EncodableType, предполагает наличие других несовпадений типов. Я рекомендую упростить это до минимального примера, который фактически демонстрирует проблему на игровой площадке. я написал это, мне пришлось угадать кучу лишнего кода.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...