Каков синтаксис do-catch для обработки ошибок в Swift?
Что проверяют
Знаете ли вы модель ошибок Swift целиком: throws, try, do-catch, сопоставление с образцом в catch и разницу между try? и try!. Следом часто спрашивают про типизированные ошибки и про Result.
Как отвечать
Базовая форма:
do {
let data = try loader.load(id)
render(data)
} catch LoadError.notFound {
showEmpty()
} catch let error as URLError where error.code == .notConnectedToInternet {
showOffline()
} catch {
log(error)
}Что проговорить:
tryобязателен: каждый вызов бросающей функции помечается явно, по коду видно, где может вылететь ошибка;catchработает какswitch: блоки проверяются сверху вниз, поддерживают паттерны,as,whereи несколько паттернов через запятую. Последнийcatchбез паттерна получает неявную константуerror;- полнота: если блоки
catchпокрывают не все ошибки, окружающая функция должна бытьthrows, иначе код не скомпилируется; try?иtry!: первый превращает результат в опционал и глотает ошибку, второй при ошибке роняет приложение, его место только там, где ошибка означает баг программиста;- типизированные ошибки: в Swift 6 есть
throws(LoadError), и внутриdo throws(LoadError)константаerrorполучает конкретный тип вместоany Error; - смежное:
deferдля освобождения ресурсов,rethrowsдля функций высшего порядка,try awaitв асинхронном коде.
Добавьте, что ошибки в Swift это не исключения в духе Java или C++: нет дорогой раскрутки стека в поиске обработчика, ошибка возвращается как значение по особому соглашению о вызове.
Где спотыкаются
Пишут catch let error в последнем блоке. Это работает, но выдаёт, что вы не знаете про неявный error.
Используют try? везде, где лень обрабатывать ошибку. Пользователь видит пустой экран, а в логах ничего нет.
Показывают пользователю error.localizedDescription для собственного enum. Без LocalizedError там окажется невнятная системная фраза вроде The operation couldn't be completed, а не ваш текст.