Swift - рефакторинг общего кода в протокол - PullRequest
0 голосов
/ 10 ноября 2018

У меня есть несколько классов, в которых есть код, который вызывает общий сетевой класс для вызова API GET. Ниже приведен пример одного из них:

public typealias Api1Result = (Result<Api1Model>) -> Void

private var path = "the/path/api1"

public enum Api1ServiceError: String, Error {
    case error = "Sorry, the api1 service returned something different than expected"
}

extension Api1Model {

    public static func getApi1(networkClient: NetworkClient = networkClient, completion: @escaping Api1Result) {
        networkClient.getPath(path) { result in
            switch result {
            case .success(let data):
                do {
                    let api1Model = try JSONDecoder().decode(Api1Model.self, from: data)
                    completion(.success(api1Model))
                } catch {
                    completion(.failure(Api1ServiceError.error))
                }
            case .failure(let error):
                completion(.failure(error))
            }
        }
    }    
}

Вот перечисление Результата, если интересно:

public enum Result<Value> {
    case success(Value)
    case failure(Error)
}

Существует несколько других классов моделей, и единственное отличие состоит в том, что декодируется фактический класс модели (в данном случае Api1Model), а также типализации завершения (Api1Result). Он делает то же самое с несколькими другими, просто вызывает метод networkClient.getPath(), проверяет успех / неудачу и вызывает закрытие завершения.

Интересно, есть ли какие-нибудь эксперты по протоколам, которые могли бы помочь в упрощении этого и рефакторинге, чтобы у меня не было одинакового кода для нескольких классов?

1 Ответ

0 голосов
/ 10 ноября 2018

Использовать расширение протокола (не проверено)

protocol ApiModel {
    associatedtype ApiType : Decodable = Self

    static var path : String { get }
    static func getApi1(networkClient: NetworkClient, completion: @escaping (Result<ApiType>) -> Void)

}

extension ApiModel where Self : Decodable {   
    static func getApi1(networkClient: NetworkClient, completion: @escaping (Result<ApiType>) -> Void) {
        networkClient.getPath(path) { result in
            switch result {
            case .success(let data):
                do {
                    let api1Model = try JSONDecoder().decode(ApiType.self, from: data)
                    completion(.success(api1Model))
                } catch {
                    completion(.failure(Api1ServiceError.error))
                }
            case .failure(let error):
                completion(.failure(error))
            }
        }
    }
}

Приведите все ваши классы в соответствие ApiModel и добавьте статическое свойство path. Псевдоним типа будет выведен.

...