Как завершится программа, если выражение с try! выбросит ошибку?
Если выражение с try! выбросит ошибку, выполнение завершится аварийно во время работы программы. Ошибка не будет передана вызывающему коду и не попадёт в обычный обработчик catch.
В Swift ошибки обрабатываются явно: бросающий вызов обычно помечается try, а функция может передать ошибку выше через throws. Это делает потенциально небезопасные места заметными в исходном коде.
try! появился как средство сообщить компилятору: разработчик уверен, что конкретный вызов не завершится ошибкой. Такой вариант удобен там, где успешное выполнение является доказанным инвариантом, но он сознательно отключает безопасную обработку сбоя.
Если это предположение окажется неверным, приложение не получит объект ошибки, который можно классифицировать, залогировать или преобразовать в состояние интерфейса. Вместо этого произойдёт аварийное завершение, что особенно опасно в коде, зависящем от сети, пользовательского ввода, файловой системы или внешних сервисов.
Риск часто возникает после изменения реализации функции. В момент написания try! вызов мог быть гарантированно успешным, но позднее API начинает бросать новую ошибку, и ранее безопасный участок превращается в точку аварии.
try! принудительно превращает бросающий вызов в обычное выражение, рассчитывая на отсутствие ошибки. Если вызываемая функция возвращает значение, оно используется дальше; если она выбрасывает ошибку, Swift вызывает аварийное завершение вместо обычной передачи ошибки по стеку вызовов.
Минимальный пример:
До print выполнение не дойдёт: вызов parse завершится ошибкой, а try! приведёт к runtime trap. В отличие от try?, результат не превращается в nil; в отличие от обычного try, ошибка не требует окружающего do-catch или throws.
Использовать try! допустимо только при действительно проверяемом инварианте, например когда успешность операции гарантируется самим контрактом приложения и нарушение этого контракта означает программную ошибку. Для внешних и изменяемых источников данных предпочтительнее do-catch, try? или явное возвращение ошибки через Result.
Модуль загружает обязательный ресурс, который, по договорённости, должен входить в поставку приложения. Разработчик выбирает try!, потому что отсутствие ресурса означает ошибку сборки или упаковки, а не штатный сценарий работы.
Вариант с do-catch безопаснее для эксплуатации: приложение может показать понятное сообщение или использовать резервный ресурс. Его минус — необходимость определить поведение восстановления, хотя при нарушении поставочного инварианта восстановление может быть бессмысленным.
Вариант с try? не приводит к аварии, но превращает конкретную причину сбоя в отсутствие значения. Это удобно для необязательного ресурса, однако плохо подходит для обязательного: ошибка может быть незаметно проигнорирована.
Выбранный вариант зависит от контракта. Для действительно обязательного ресурса на этапе разработки допустим try!, если нарушение гарантии должно немедленно выявляться; для пользовательского сценария выбран бы do-catch с диагностикой и резервным поведением.
try!, внешним catch?Нет. catch перехватывает ошибки, которые продолжают распространяться как обычные Swift-ошибки. try! вместо этого преобразует нарушение предположения в аварийное завершение, поэтому внешний обработчик не получает такую ошибку.
try! от try??try! сохраняет тип успешного значения, но аварийно завершает выполнение при ошибке. try? подавляет ошибку и возвращает optional: успешное значение становится some, а ошибка — nil. Поэтому try? безопаснее с точки зрения жизнеспособности процесса, но может скрыть причину сбоя и потерять различия между несколькими видами ошибок.
try!?Нет. Для try! нужна гарантия, а не высокая вероятность успеха. Если результат зависит от сети, диска, конфигурации, пользовательского ввода или изменяемого внешнего API, такая гарантия обычно отсутствует; следует выбрать явную обработку ошибки или безопасное преобразование результата.