Метод для загрузки с использованием дженериков просит больше контекста - PullRequest
0 голосов
/ 30 мая 2019

Я написал метод, использующий дженерики, чтобы сделать его многоразовым для любой загрузки.Он загружает массивы json и возвращает общий объект или ошибку.Это мой класс для загрузки массивов json с сервера:

import Foundation
enum Result<T> {
    case success(T)
    case failure(Error)
}
class LTLNetworkClient: NSObject {

    fileprivate var session : URLSession
    fileprivate var objectTask : URLSessionDataTask?

    override init() {
        let config = URLSessionConfiguration.ephemeral
        config.timeoutIntervalForResource = 5
        config.timeoutIntervalForRequest = 5
        self.session = URLSession.init(configuration: config)
    }

    /**
    Download asynchronously json object from Server and returns it into generic data models
    */
    func getData<K: Codable>(request: URLRequest, completion: @escaping (Result<[K]>) -> Void) {
        let sessionDataTask = URLSession.shared.dataTask(with: request) { (responseData, response, responseError) in
            if let jsonData = responseData {
                let decoder = JSONDecoder()
                do {
                    let response = try decoder.decode([K].self, from: jsonData)
                    let result: Result<[K]> = Result.success(response)
                    completion(result)
                } catch {
                    completion(.failure(error))
                }
            } else if let error = responseError {
                completion(.failure(error))
            } else {
                let error = NSError(domain: "Cannot form jsonData with Response Data", code: 501, userInfo: nil)
                completion(.failure(error))
            }
        }
        sessionDataTask.resume()
    }
}

И вот как я вызываю метод и получаю ошибку:

enter image description here

Кто-нибудь знает, как это исправить и почему появляется эта ошибка?Заранее большое спасибо

1 Ответ

2 голосов
/ 30 мая 2019

Вот ваше объявление метода:

func getData<K: Codable>(request: URLRequest, completion: @escaping (Result<[K]>) -> Void)

Этот метод имеет параметр типа K, который используется только в типе аргумента completion. Когда компилятор видит вызов getData, он должен определить конкретный тип для K на основе типа аргумента замыкания, которое вы передаете как completion.

А вот ваш звонок:

networkClient.getData(request: urlRequest) { (result) in
    // Do stuff
}

В этом вызове закрытие completion составляет { (result) in }. Какой тип result? Об этом нет никакой информации, поэтому все, что знает компилятор, это то, что result должен иметь тип Result<[K]> для некоторого типа K. У него нет способа вывести конкретный тип для K, поэтому он выдает ошибку.

Вы можете сделать тип явным, как этот:

networkClient.getData(request: urlRequest) { (_ result: Result<[SomeConcreteCodableType]>) -> Void in
    // Do stuff
}

, где SomeConcreteCodableType - это конкретный тип, соответствующий Codable. Соответствие Codable требуется из-за ограничения в объявлении getData.

Другое решение состоит в том, чтобы изменить getData на другой аргумент, который позволяет вызывающей стороне указывать K напрямую:

func getArray<K: Codable>(of: K.Type, for request: URLRequest,
    completion: @escaping (Result<[K]>) -> Void) {
    ...
}

Тогда вы называете это так:

networkClient.getArray(of: SomeConcreteCodableType.self, for: request) { result in
    // Do stuff
}
...