В блоке do-catch общий обработчик расположен перед обработчиком конкретной ошибки. Как это влияет на достижимость последнего обработчика?
Общий обработчик, соответствующий любой ошибке, перехватит ошибку раньше, поэтому обработчик конкретного типа станет недостижимым. В Swift обработчики catch проверяются сверху вниз, поэтому сначала размещают наиболее специфичные шаблоны, а общий catch — последним.
Модель do-catch в Swift отделяет место возникновения ошибки от места, где приложение принимает решение о восстановлении или преобразовании сбоя. Порядок обработчиков является частью этой модели: он позволяет последовательно проверять варианты ошибки, подобно сопоставлению с шаблонами.
Такой подход решает проблему неявного выбора обработчика. Код явно показывает, какие ошибки обрабатываются отдельно, а какие попадают в резервную ветку.
Если поставить catch, который принимает любую ошибку, перед специализированным обработчиком, до последнего никогда не дойдёт управление. Это не просто менее точное поведение: компилятор Swift обычно диагностирует последующий обработчик как недостижимый.
Неверный порядок также может скрыть важную бизнес-логику. Например, ошибка истёкшей сессии должна привести к повторной авторизации, но общий обработчик может перехватить её раньше и показать пользователю обычное сообщение о сбое.
Обработчики catch сопоставляются в порядке объявления. Сначала проверяют конкретные случаи перечисления или конкретные типы ошибок, затем — более общие варианты, а безусловный catch оставляют последним.
В этом примере ошибка сначала проверяется на совпадение с StorageError.missing, затем с StorageError.corrupted, и только после этого попадает в общий обработчик. Если поменять местами общий catch и специализированный, общий шаблон поглотит все ошибки, а следующий обработчик станет недостижимым.
Специализированный обработчик может дополнительно использовать связанные значения и условия where. Однако чем шире шаблон, тем позже его следует размещать. Это правило сохраняет предсказуемость обработки и помогает компилятору выявлять логические ошибки в структуре do-catch.
Сервис загрузки данных различает отсутствие локального файла, повреждение кеша и неизвестную ошибку. Вариант с одним общим catch проще, но не позволяет выбрать разные стратегии восстановления. Вариант с отдельными обработчиками даёт точное поведение, однако требует поддерживать порядок и полноту ветвей.
Практичное решение — расположить обработчики от наиболее специфичных к наиболее общему: для отсутствующего файла запустить загрузку из сети, для повреждённого кеша удалить кеш и повторить операцию, а неизвестную ошибку передать на общий слой диагностики. В результате каждая известная причина получает предсказуемую реакцию, а новые или неожиданные ошибки не теряются.
1. Можно ли поставить общий catch первым, если специализированный обработчик всё равно нужен для документации?
Нет. Общий catch не является только документационным элементом: он реально перехватывает любую ошибку. Специализированную ветку нужно либо переместить выше, либо удалить, если отдельная обработка больше не требуется.
2. Влияет ли тип переменной ошибки на порядок обработчиков?
Нет, порядок остаётся последовательным независимо от того, хранится ли ошибка в Error или в конкретном типе. На каждом шаге проверяется шаблон текущего catch, а после первого совпадения остальные обработчики не рассматриваются.
3. Можно ли заменить общий catch на обработчик конкретного перечисления и считать обработку полной?
Только если функция гарантированно выбрасывает ошибки этого типа и контракт это сохраняет. В Swift throws без типизированного ограничения не гарантирует конкретный тип ошибки, поэтому для надёжного перехвата неизвестных ошибок нужен резервный общий catch.