Swift объединяет обработку ошибок кода состояния HTTP - PullRequest
1 голос
/ 31 марта 2020

Я читал эту статью: https://www.raywenderlich.com/4161005-mvvm-with-combine-tutorial-for-ios о Рэй Вендерлих о том, как использовать комбайн. У них есть пример, где он выбирает данные из API, но не обрабатывает коды состояния HTTP. Я хотел добавить его, но пока что не могу этого сделать.

В соответствии с этим ответом вы можете добавить tryMap, но затем XCode начинает показывать ошибки вроде: Generic parameter 'T' could not be inferred.

Ниже кода:

extension WeatherFetcher: WeatherFetchable {
  func weeklyWeatherForecast(
    forCity city: String
  ) -> AnyPublisher<WeeklyForecastResponse, WeatherError> {
    return forecast(with: makeWeeklyForecastComponents(withCity: city))
  }

  private func forecast<T>(
    with components: URLComponents
  ) -> AnyPublisher<T, WeatherError> where T: Decodable {
    guard let url = components.url else {
      let error = WeatherError.network(description: "Couldn't create URL")
      return Fail(error: error).eraseToAnyPublisher()
    }
    return session.dataTaskPublisher(for: URLRequest(url: url))
      .mapError { error in
        .network(description: error.localizedDescription)
    }
    .flatMap(maxPublishers: .max(1)) { pair in
      decode(pair.data)
    }
    .eraseToAnyPublisher()
  }
}

И я пытался добавить

.tryMap { data, response in
    guard let httpResponse = response as? HTTPURLResponse,
        200..<300 ~= httpResponse.statusCode else {
            switch (response as! HTTPURLResponse).statusCode {
            case (400...499):
                throw ServiceErrors.internalError((response as! HTTPURLResponse).statusCode)
            default:
                throw ServiceErrors.serverError((response as! HTTPURLResponse).statusCode)
            }
    }
    return data
}

1 Ответ

0 голосов
/ 31 марта 2020

Я думаю, вы можете просто заменить блок flatMap на tryMap. И вместо того, чтобы возвращать данные из tryMap, они должны быть декодированы T. Так что return data строка должна быть return try JSONDecoder().decode(T.self, from: data)

private func forecast<T>(with components: URLComponents) -> AnyPublisher<T, WeatherError> where T: Decodable {
guard let url = components.url else {
    let error = WeatherError.network(description: "Couldn't create URL")
    return Fail(error: error).eraseToAnyPublisher()
}
return session.dataTaskPublisher(for: URLRequest(url: url))
    .tryMap { data, response in
        guard let httpResponse = response as? HTTPURLResponse,
            200..<300 ~= httpResponse.statusCode else {
                switch (response as! HTTPURLResponse).statusCode {
                case (400...499):
            throw ServiceErrors.internalError((response as! HTTPURLResponse).statusCode)
                default:
                    throw ServiceErrors.serverError((response as! HTTPURLResponse).statusCode)
                }
        }
        return try JSONDecoder().decode(T.self, from: data)
}
.mapError { error in
    WeatherError() // some kind of error
}
.eraseToAnyPublisher()

}

...