Что теряет вызывающий код при замене обработки ошибки оператором try??
При использовании try? любая ошибка преобразуется в отсутствие значения — nil. Вызывающий код теряет сам объект ошибки и возможность различать причины сбоя, поэтому такой подход подходит только тогда, когда все варианты неуспеха намеренно равнозначны.
Механизм throws позволяет функции передавать ошибку по цепочке вызовов, не смешивая ошибку с обычным возвращаемым значением. Оператор try? появился как краткий способ распространить ошибку в форме опционального результата, когда подробная обработка причины не нужна.
В современных версиях Swift результат try? для функции, возвращающей опциональное значение, не образует лишний уровень вложенности: отсутствие значения остаётся nil, а неуспех также представлен nil. Это делает запись удобнее, но усиливает риск потери различий между сценариями.
Предположим, функция может завершиться по нескольким причинам: ресурс отсутствует, сеть недоступна или данные повреждены. После замены do-catch на try? все эти случаи становятся одинаковыми для вызывающего кода.
Если функция и без того возвращает опциональное значение, возникает дополнительная неоднозначность: nil может означать нормальное отсутствие результата или ошибку. Неверный выбор приводит к скрытым сбоям, неправильным сообщениям пользователю и невозможности корректно выбрать повторную попытку.
try? перехватывает ошибку, выброшенную выражением, и преобразует успешный результат типа T в значение типа T?. При успехе получается .some(value), при ошибке — nil; исходный тип ошибки недоступен.
В отличие от do-catch, try? не позволяет выполнить разную логику для разных ошибок и не даёт передать ошибку дальше. В отличие от try!, он не завершает программу аварийно при ошибке, но может скрыть важную причину сбоя.
Использовать try? разумно для необязательной операции, где ошибка эквивалентна отсутствию результата: например, при попытке найти необязательную настройку. Для диагностики, повторных попыток, аналитики или разных пользовательских сообщений следует применять do-catch либо передавать ошибку через Result.
Сервис загружает необязательный локальный аватар. Если файла нет, приложение должно показать стандартное изображение; ошибка чтения хранилища не требует отдельного пользовательского сценария. Здесь try? упрощает код, потому что оба случая трактуются как отсутствие аватара.
Вариант с do-catch сохраняет причины ошибки и позволяет вести журнал, но добавляет обработку, которая может быть не нужна на этом уровне. Вариант с Result удобен для передачи результата в другой слой, однако для локальной одноразовой проверки часто избыточен.
Выбор try? оправдан только после явного решения, что потеря причины безопасна. Если же отсутствие файла и повреждение хранилища требуют разных действий, нужно выбрать do-catch, а не скрывать ошибку за nil.
try? определить, какая именно ошибка произошла?Нет. Оператор преобразует любую выброшенную ошибку в nil, поэтому тип и содержимое ошибки теряются. Для сопоставления с конкретными случаями нужен do-catch, а для передачи результата без немедленной обработки — Result.
В актуальном Swift результат остаётся одним опциональным уровнем: успешный nil и ошибка также могут выглядеть как nil. Поэтому try? особенно опасен для функций с результатом T?, если вызывающему коду нужно отличать нормальное отсутствие значения от сбоя.
try? отличается от try! с точки зрения последствий ошибки?try? превращает ошибку в nil и продолжает выполнение, а try! утверждает, что ошибки не будет, и при её возникновении аварийно завершает выполнение. try! допустим только при доказанной инвариантности, тогда как try? требует уверенности, что причина ошибки действительно не нужна.