#swift #combine
#swift #объединить
Вопрос:
У меня особая ситуация, когда возвращающая функция предоставляет что-то вроде AnyPublisher<Response, Error>
. Но из вызывающей функции я хочу вернуться AnyPublisher<Response, Never>
.
//just an example
func getList(_ request: QueryRequest) -> AnyPublisher<Response, Never> {
return executeQuery(request).eraseToAnyPublisher()
}
func executeQuery(_ request: QueryRequest) -> AnyPublisher<Response, Error> {
return someData().eraseToAnyPublisher()
}
Когда я делаю это, я получаю Cannot convert return expression of type 'AnyPublisher<Response, Error>' to return type 'AnyPublisher<Response, Never>'
Как мне выполнить преобразование в AnyPublisher<Response, Never>
без изменения вызываемой функции?
Примечание: я не могу изменить возвращаемый тип вызываемой функции, поскольку он используется другими методами, использующими Error
Комментарии:
1. Зависит от того, что вы хотите сделать, когда приходит ошибка
executeQuery
. Вы игнорируете и завершаете, вы заменяете его некоторым значением и завершаете?2. Я хочу проигнорировать и продолжить, в случае возникновения ошибки для этого.
3. Что означает продолжить? Если
executeQuery
отправляется ошибка, ее издатель завершен. Вы можете повторить попытку (которая приведет к повторной подписке), и в зависимости от того, что он делает, он может выполнить другой запрос. Но тогда возникает больше вопросов… сколько раз повторять попытку? Вы ждете между повторными попытками?4. В данном конкретном случае я не ожидаю ошибки. Но, однако, если я когда-нибудь получу его, есть ли способ, которым я могу справиться с этим сам по
getList
себе и вернутьсяAnyPublisher<Response, Never>
?5. Если вы не ожидаете ошибки, вы можете использовать
.assertNoFailure("wtf?")
— что приведет к фатальной ошибке, если произошел сбой, отправленный из восходящего потока… Опять же, зависит от того, что означает «обрабатывать» ошибку
Ответ №1:
Чтобы преобразовать из вышестоящего издателя, который может выйти из строя, в тот, который никогда не выходит из строя, вам необходимо решить, как обрабатывать случай, когда возникает ошибка (поскольку она не может быть отправлена вашему нижестоящему издателю).
Если вы «знаете», что это никогда не произойдет в вашем конкретном случае, вы можете утверждать, что ошибки не будет:
return executeQuery(request)
.assertNoFailure("this shouldn't have happened")
.eraseToAnyPublisher()
Или вы можете просто проигнорировать его (поймав и заменив его Empty
publisher), что завершит ваш конвейер:
return executeQuery(request)
.catch { _ in Empty<Response, Never>() }
.eraseToAnyPublisher()
Вы также можете заменить ошибку некоторым значением с помощью .replaceError(with:)
Обратите внимание, что при возникновении ошибки от executeQuery
publisher (восходящий поток) он завершает конвейер, поэтому ваш нисходящий поток также получит завершение.
Вы не можете продолжать получать значения из вышедшего из строя восходящего потока, о чем вы спрашивали в комментариях. Вы можете рассмотреть возможность повторной подписки, .retry
если считаете, что ошибка была временной (например, сервер недоступен)