Несоответствие типов ввода и вывода в комбинированной выборке данных

Я новичок в реактивном программировании и Combine, у меня есть следующий метод, который извлекает данные о погоде из API.

  • Во-первых, я проверяю, что если я получаю 200, если нет, то выдает ошибку.
  • Если я получаю правильные данные, я декодирую их с помощью JSONDecoder, но просто чтобы проверить, есть ли какие-то проблемы с декодированием JSON, я возвращаю объект по умолчанию.
  • Наконец, сопоставление ошибки, которая возникает на первом шаге, но я получаю следующую ошибку в методе экземпляра функции flatMAp

flatMap (maxPublishers: _ :) »требует, чтобы типы Publishers.TryMap.Failure (также известные как« Ошибка ») и« Just.Failure »(также известные как« Никогда ») были эквивалентными

private func fetchDataFor(urlStr: String) -> AnyPublisher<WeatherData, Error> {
            let url = URL(string: urlStr)!
            return URLSession.shared.dataTaskPublisher(for: url)
                .tryMap({ (data, response)  in
                    let response = (response as? HTTPURLResponse)
                    if response?.statusCode != 200 {
                        throw NSError(domain: "Error", code: response!.statusCode, userInfo: .none)
                    }
                    return data
            })
            .flatMap{ data in
                Just(data)
                    .decode(type: WeatherData.self, decoder: JSONDecoder())
                    .catch{ error in
                        return Just(defaultWeatherData)
                    }
            }
            .mapError{ error in
                return error
            }
            .receive(on: RunLoop.main)
            .eraseToAnyPublisher()
        }

Может ли кто-нибудь указать, что здесь не так, или я использую какой-то неправильный подход. Спасибо


person Madu    schedule 05.03.2020    source источник


Ответы (1)


Измените свою функцию на это:

private func fetchDataFor(urlStr: String) -> AnyPublisher<WeatherData, Error> {
    let url = URL(string: urlStr)!
    return URLSession.shared.dataTaskPublisher(for: url)
        .tryMap({ (data, response)  in
            let response = (response as? HTTPURLResponse)
            if response?.statusCode != 200 {
                throw NSError(domain: "Error", code: response!.statusCode, userInfo: .none)
            }
            return data
        })
        .decode(type: WeatherData.self, decoder: JSONDecoder())
        .receive(on: RunLoop.main)
        .eraseToAnyPublisher()
}

Combine имеет полезный встроенный .decode метод, с помощью которого вы можете преобразовать данные в локальную модель.

Кроме того, хорошей практикой является не использовать .receive(on: RunLoop.main) в методах запроса, а позволить вашей ViewModel / Interactor (просто потребителю ответа) решать, какой поток он хочет получить ответ.

person Dmitriy Lupych    schedule 05.03.2020
comment
Привет, спасибо, на самом деле у меня была эта реализация, прежде чем я решил проверить, есть ли проблема с синтаксическим анализом во время синтаксического анализа JSON, тогда я хочу получить объект по умолчанию. Имейте в виду, что я написал функцию с плоской картой - person Madu; 06.03.2020
comment
Кроме того, this mapError соответствует FlatMap или tryMap или любой ошибке, произошедшей в цепочке событий. - person Madu; 06.03.2020
comment
Что вы можете заменить свою flatMap на эту: .flatMap {данные в Just (data) .decode (type: WeatherData.self, decoder: JSONDecoder ()) .catch {error in return Just (defaultWeatherData) .setFailureType (to: Error .self) .eraseToAnyPublisher ()}} - person Dmitriy Lupych; 06.03.2020