Как правильно использовать switch для обработки разных состояний результата в Swift
Что проверяют
Знаете ли вы, что switch в Swift исчерпывающий и что это инструмент безопасности, а не замена цепочке if. Следом обычно спрашивают, когда допустим default и как отличить одну ошибку от другой.
Как отвечать
Для результата операции в стандартной библиотеке есть Result<Success, Failure: Error>, свой enum под это писать не нужно. В ветке case .success(let user) показываете данные, в case .failure(let error) ошибку. Дальше детали:
- исчерпываемость: компилятор требует покрыть все случаи. Для собственных enum
defaultлучше не писать, тогда новый case сломает сборку везде, где его забыли обработать; @unknown default: для enum из системных фреймворков, которые могут получить новые значения в следующем SDK. Компилятор предупредит, если известный случай не обработан явно;- сопоставление с образцом:
case .failure(let error as URLError) where error.code == .notConnectedToInternetотделяет отсутствие сети от прочих ошибок, аcase .success(let items) where items.isEmptyвыносит пустое состояние в свою ветку; - объединение веток:
case .loading, .idle:для одинаковой обработки, привязки в объединённых ветках должны совпадать по имени и типу; switchкак выражение: начиная со Swift 5.9 можно писатьlet title = switch state { ... }, если каждая ветка состоит из одного выражения.
Для экрана Result обычно заворачивают в состояние: enum ViewState { case idle, loading, loaded([Item]), failed(Error) }. Загрузка это стадия, а не результат, и смешивать её с успехом и ошибкой в одном типе неудобно. Если нужен один случай, короче if case .failure(let error) = result, а try result.get() превращает Result обратно в бросающий вызов.
Где спотыкаются
Ставят default в switch по своему enum на всякий случай. Новый case тихо уходит в default, и компилятор уже не подскажет, где его забыли.
Различают ошибки через error.localizedDescription и сравнение строк. Текст локализован и меняется между версиями, сопоставлять нужно тип и код ошибки.
Ждут поведения как в C. В Swift ветки не проваливаются, break в конце не нужен, а явный fallthrough не может перейти в ветку, которая связывает значения.