#ios #swift #generics #refactoring #combine
#iOS #быстрый #дженерики #рефакторинг #объединять
Вопрос:
У меня есть эта уродливая конструкция возврата универсального типа в виде твердой модели, у кого-нибудь есть идеи по рефакторингу, чтобы быть более декларативным?
extension NetworkingService { func login(email: String, password: String) -gt; AnyPublisherlt;UserModel, APIErrorgt; { func convertToModel() -gt; AnyPublisherlt;ResponseObjectlt;UserResponsegt;, APIErrorgt; { return request(with: AuthRequests.login(email: email, password: password)).eraseToAnyPublisher() } return convertToModel().map { UserModel(with: $0.data!) }.eraseToAnyPublisher() } func requestlt;Tgt;(with endpoint: Endpoint) -gt; AnyPublisherlt;T, APIErrorgt; where T : Decodable { //... returning any publisher with Decodable } }
Ответ №1:
Ваша requestlt;Tgt;(with:)
функция использует только T
в возврате. Хотя это выполнимо, это означает, что вызывающий код должен вызывать то, что T
есть, что делает ваш вызывающий код «уродливым».
Из того, что вы опубликовали, у меня сложилось впечатление, что единственное Endpoint
, что делает ваш тип, — это создает URL-запрос. Если бы он также определял форму ожидаемых возвращаемых данных, то вся конструкция была бы чище.
Я предлагаю сделать так, чтобы ваш Endpoint
тип выглядел вот так:
public struct Endpointlt;Responsegt; { public let request: URLRequest public let response: (Data) throws -gt; Response public init(request: URLRequest, response: @escaping (Data) throws -gt; Response) { self.request = request self.response = response } }
Затем, с подходящими обновлениями в другом месте, вы могли бы сделать что-то вроде этого:
extension NetworkingService { func login(email: String, password: String) -gt; AnyPublisherlt;UserModel, APIErrorgt; { request(with: AuthRequests.login(email: email, password: password)) .map { $0.response.model } .eraseToAnyPublisher() } func requestlt;Tgt;(with endpoint: Endpointlt;Tgt;) -gt; AnyPublisherlt;T, APIErrorgt; where T: Decodable { //... returning any publisher with Decodable } }