Что происходит при вызове функции, объявленной как throwing, если вызывающий код не обрабатывает возможную ошибку?
Вызов throwing-функции должен быть явно обозначен через try, try? или try!. Если вызывающий код не выбрал один из этих вариантов, Swift отклонит программу на этапе компиляции.
try не обрабатывает ошибку сам по себе: он только подтверждает, что ошибка будет поймана текущим do-catch или передана дальше из другой throwing-функции.
Swift использует явную модель обработки ошибок вместо неявного распространения исключений. Такой подход отделяет обычный результат функции от альтернативного пути завершения и делает потенциально опасные места видимыми непосредственно в коде.
Для представления ошибок используется протокол Error, а возможность выбросить ошибку фиксируется в объявлении функции ключевым словом throws. Это позволяет компилятору контролировать каждый вызов throwing-функции.
Функция может завершиться не обычным возвращаемым значением, а ошибкой. Если разрешить вызывать её без специальной пометки, ошибка могла бы незаметно пройти через несколько уровней кода и привести к неожиданному поведению.
Swift поэтому требует явно выбрать стратегию: обработать ошибку через do-catch, передать её вызывающему коду с помощью throws, преобразовать в nil через try? или сознательно принять риск аварийного завершения через try!.
try применяется, когда ошибка должна либо быть обработана в текущем контексте, либо передана дальше. Если окружающая функция сама не объявлена как throwing, вызов обычно помещают в do-catch.
try? подавляет ошибку и преобразует результат в optional: при успехе получается значение, при ошибке — nil. Это удобно, когда причина отказа не нужна вызывающему коду, но такой вариант теряет диагностическую информацию.
try! утверждает, что ошибка невозможна. При фактическом выбрасывании ошибки приложение аварийно завершится, поэтому этот вариант допустим только при доказуемом инварианте.
У throwing-функции ошибка не является обычным возвращаемым значением. Она не смешивается с типом результата: функция может иметь результат Int, а отдельно сигнализировать о возможном завершении через ошибку.
Сервис загружает пользовательский идентификатор из текста. Вариант с try! краток, но при повреждённом ответе сервера завершит приложение. Вариант с try? не аварийный, однако скрывает причину ошибки и затрудняет диагностику.
Оптимальное решение — передать ошибку на уровень, который умеет выбрать пользовательское поведение, например показать сообщение или повторить запрос. Это сохраняет причину сбоя и не смешивает техническую ошибку с обычным отсутствием значения.
try обработку ошибки?Нет. try только отмечает место, где может возникнуть ошибка. Обработка выполняется конструкцией do-catch, а передача ошибки выше — через throwing-контекст. Поэтому код с try всё ещё может завершиться ошибкой.
do-catch?Нет, если вызов использует обычный try. Обычная функция не может неявно передать ошибку дальше: она должна обработать её локально, применить try? или try!. Альтернативно её объявляют как throwing, чтобы она сама стала частью цепочки распространения ошибок.
try? отличается от обработки ошибки через do-catch?try? намеренно сводит все варианты ошибки к nil и потому теряет конкретную причину. do-catch позволяет сопоставлять разные типы и значения ошибок, выполнять разные действия для каждого случая и сохранять диагностический контекст. Поэтому try? подходит для необязательной операции, а do-catch — когда ошибка влияет на поведение программы.