Использование Combine для запуска загрузки при активации приложения без компиляции - PullRequest
0 голосов
/ 02 апреля 2020

Я пытаюсь запустить загрузку, когда мое приложение становится активным, но я не могу понять, как это сделать.

Это мой код

NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification).map{ _ in
    return self.urlSession.dataTaskPublisher(for: url)
}
.tryMap{ element in
    guard let httpResponse = element.response as? HTTPURLResponse,
    httpResponse.statusCode == 200 else {
        throw URLError(.badServerResponse)
    }

.....

У меня нет Идея, как заставить это работать. Я постоянно получаю сообщение об ошибке компиляции:

Value of type 'URLSession.DataTaskPublisher' has no member 'response'

Почему мой оператор возврата возвращает полного издателя, а не его результат?

Если я удаляю NotificationCenter часть и вызовите tryMap прямо на dataTaskPublisher вот так:

        self.urlSession.dataTaskPublisher(for: url)
        .tryMap{ element in

компилятор не жалуется.

Довольно запутался здесь :)

1 Ответ

1 голос
/ 03 апреля 2020

Почему мой оператор return возвращает полного издателя, а не его результат?

Он возвращает полного издателя, потому что вы сказали, чтобы он возвратил полного издателя. map Output - это то, что возвращает преобразование map. Ваше преобразование map возвращает DataTaskPublisher, поэтому Output из map равно DataTaskPublisher. Следовательно, Input - tryMap - тип переменной element - это DataTaskPublisher. Грубо говоря, тип после map (до tryMap) равен

Publisher<Publisher<(data: Data, response: URLResponse), URLError>, Never>

(Это не реальный тип, потому что Publisher не является конструктором реального типа.)

Вам нужно выровнять это значение в

Publisher<(data: Data, response: URLResponse), Error>

. Вам нужно будет использовать setFailureType(to:), чтобы преобразовать тип ошибки издателя уведомлений из Never в Error. И вам нужно будет использовать mapError для преобразования типа сбоя DataTaskPublisher из URLError в Error.

После того, как вы сопоставили типы отказов, есть несколько операторов это может сгладить вложенные издатели. Вероятно, вы ищете switchToLatest:

func data(for url: URL) -> AnyPublisher<Data, Error> {
    NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification)
        .setFailureType(to: Error.self)
        .map({ _ in
            self.urlSession.dataTaskPublisher(for: url)
                .mapError { $0 as Error }
        })
        .switchToLatest()
        .tryMap({ element in
            guard let httpResponse = element.response as? HTTPURLResponse,
                httpResponse.statusCode == 200 else {
                    throw URLError(.badServerResponse)
            }
            return element.data
        })
        .eraseToAnyPublisher()
}
...