Использование примеров кода, чтобы показать, как бороться с этими неудачными случаями
При начале работы с Combine вы быстро столкнетесь с проблемами обработки ошибок. Каждый поток Combine получает либо значение, либо ошибку, и в отличие от таких фреймворков, как RxSwift, вам необходимо указать ожидаемый тип ошибки.
Чтобы подготовить вас к этим случаям, в этой части я рассмотрю доступные в Combine параметры, позволяющие выявлять, игнорировать и обрабатывать ошибки в потоке. Мы также расскажем о некоторых важных вещах, которые вам нужно знать при возникновении ошибки в вашем потоке.
Только начинаете работать с Combine? Вы можете сначала взглянуть на Начало работы с фреймворком Combine в Swift или мою Игровую площадку Combine.
Объедините потоки и типизированные ошибки
Большое различие между такими фреймворками, как RxSwift и Combine, состоит в том, что в потоках необходимо указывать типизированные определения ошибок. Если мы сравним Observable
с его эквивалентом в Combine AnyPublisher
, мы увидим разницу в объявлении типа.
public class Observable<Element> : ObservableType
struct AnyPublisher<Output, Failure> where Failure : Error
AnyPublisher
требует, чтобы мы указали тип ошибки Failure
, в то время как Observable
принимает только общий тип Element
.
Swift требует от нас думать об обработке ошибок, что мы можем принять за что-то хорошее. Однако это не мешает нам определить ожидаемый тип как просто Swift.Error
, что в основном сводится к тому же поведению, что и в RxSwift.
Как только вы потребуете, чтобы ваш поток ожидал ошибки определенного типа, вы столкнетесь с ошибками приведения, поскольку каждый оператор должен возвращать тот же тип ошибки, что и ведущий поток. Давайте углубимся в операторы Combine для обработки ошибок.
Отображение ошибок с помощью mapError
Чтобы сопоставить ошибку с ожидаемым типом ошибки, мы можем использовать оператор mapError
. В следующем примере у нас есть сквозная тема, которая ожидает вывода URL и типа ошибки RequestError
.
Как только мы начинаем отображать этот поток в URLSessionDataTaskPublisher
, мы сразу получаем ошибку, указывающую на несоответствие типа ошибки.
В этом случае решение так же просто, как использование оператора mapError
, который преобразует URLError
в RequestError
, используя случай ошибки сеанса, который мы определили ранее.
Использование оператора повтора
В приведенном выше примере мы использовали URLSessionDataTaskPublisher
. Возможно, вы захотите использовать оператор retry перед фактическим принятием ошибки при работе с запросами данных. Требуется определенное количество повторных попыток, прежде чем поток действительно потерпит неудачу.
Выявление ошибок
Если вы хотите выявлять ошибки на раннем этапе и игнорировать их после, вы можете использовать оператор catch
. Этот оператор позволяет вам вернуть значение по умолчанию, если запрос не удался. Примеры этого могут быть:
- Пустой массив для результатов поиска
- Заполнитель изображения по умолчанию, если запрос изображения не удался
Последнюю мы будем использовать в нашем примере.
Использование replaceError вместо catch
ReplaceError vs Catch: оба оператора кажутся очень похожими. Большая разница в том, что оператор replaceError(:)
полностью игнорирует ошибку. Как и в приведенном выше примере, мы не делаем ничего, кроме возврата заполнителя notFoundImage
в случае ошибки.
Мы могли бы упростить это, используя оператор replace error, чтобы напрямую отображать любые ошибки в нашем изображении-заполнителе:
Когда оператор assign (to: on :) недоступен
Типичный пример, в котором вам нужно сопоставить ошибки, - это когда вы пытаетесь присвоить исходящее значение свойству объекта. Вы попытаетесь использовать автозаполнение, и обнаружите, что оператор assign(to:on:)
недоступен. Следующая ошибка произойдет, если вы будете вынуждены написать код в любом случае:
Для ссылки на метод экземпляра «assign (to: on :)» в «Publisher» типы «RequestError» и «Never» должны быть эквивалентными.
Вы можете исправить это, обнаружив ошибку, как описано в приведенном выше примере, или просто используя оператор assertNoFailure
. Этот оператор вызовет фатальную ошибку, поэтому его следует использовать только в том случае, если это ошибка программирования. Если ожидается ошибка, вы всегда должны использовать вместо нее оператор catch.
Заключение
Мы много рассказали об обработке ошибок в Combine, и этого должно быть достаточно, чтобы помочь вам справиться со всеми этими неудачными случаями! Обязательно обрабатывайте ошибки соответствующим образом, а не просто игнорируйте их. Несчастливый поток так же важен для ваших пользователей, как и счастливый поток.
Если вы хотите поэкспериментировать с тем, что вы только что узнали, взгляните на мою Игровую площадку Swift Combine, которая включает страницу об обработке ошибок в Combine.
Чтобы узнать больше о Swift Combine, взгляните на другие мои сообщения в блоге Combine:
- Обработка ошибок в Combine объяснена с примерами кода
- Комбинируйте отладку с помощью операторов в Swift
- Создание пользовательского Combine Publisher для расширения UIKit
- Начало работы с фреймворком Combine в Swift
Изначально опубликовано на SwiftLee.
Другие сообщения и обновления: @twannl