Обработка ошибок — фундаментальный навык мобильного разработчика. По данным HackerOne (2025), 62% утечек данных происходят из-за необработанных исключений. Грамотная обработка ошибок не только предотвращает краши, но и защищает пользовательские данные. Разберём подходы для iOS, Android и React Native.
Главное
Обработка ошибок в Swift строится на четырёх ключевых механизмах: do-catch, throws, guard let и if-let. В отличие от многих языков, Swift не допускает неперехваченные исключения — каждая ошибка должна быть явно обработана или объявлена через throws. Обработка ошибок — критический навык для мобильной разработки, напрямую влияющий на стабильность приложения.
do-catch — стандартный блок для вызова функций, помеченных throws. Внутри do вызывается функция с try, и если она выбрасывает ошибку, управление переходит в catch. Можно обрабатывать разные типы ошибок через pattern matching. Если ошибка не обработана, она пробрасывается выше по стеку (Error Propagation). Для эффективной обработки ошибок в iOS используйте do-catch как основной механизм.
Throw объявляется в сигнатуре функции: func fetchData() throws -> Data. Это значит, что вызывающий код обязан обработать ошибку через try, try? или try!. try? преобразует ошибку в nil, try! вызывает crash при ошибке (используйте только если уверены в успехе). Обработка ошибок через throw — обязательная практика в Swift.
Guard let — конструкция для раннего выхода из функции, если значение равно nil. В отличие от if-let, guard let требует exit (return, throw, break) в else-ветке. Это делает код более плоским и читаемым — без вложенных if-блоков. Если optional не может быть nil — используйте force unwrap (!), только когда абсолютно уверены. В мобильном приложении guard let помогает избежать крашей при обработке опциональных значений.
Optional Chaining (user?.address?.city) и nil-coalescing (??) — синтаксический сахар для работы с optional без разворачивания. В IT Sectr мы используем guard let для валидации входных параметров API и принуждаем команду избегать force unwrap без явного комментария. Обработчик ошибок на каждом уровне защищает от непредвиденных сбоев.
Kotlin — основной язык для Android-разработки. Он наследует try-catch из Java, но добавляет более безопасные альтернативы: elvis-оператор, require, check и sealed class. Обработка ошибок в Kotlin строится на комбинации этих механизмов. В отличие от Swift, Kotlin позволяет не обрабатывать checked exceptions (все исключения unchecked). Для обработки ошибок в мобильных приложениях на Android используйте sealed class как основной паттерн.
Try-catch в Kotlin работает как expression — он возвращает значение. val result = try { fetchData() } catch (e: Exception) { fallbackValue }. Это сокращает код. Elvis-оператор (?:) — аналог nil-coalescing для nullable-типов: val name = user?.name ?: "Guest". Для обработки ошибок в мобильных приложениях try-catch как expression — наиболее лаконичный подход.
Sealed class — мощный инструмент для моделирования состояний успеха и ошибки. sealed class NetworkResult { data class Success(val data: T) : NetworkResult(); data class Error(val message: String) : NetworkResult() }. При использовании в when-выражении компилятор проверяет полноту ветвей. Обработка ошибок через sealed class гарантирует, что ни одно состояние не останется без внимания.
// Sealed class + try-catch — типовой паттерн для Android
sealed class NetworkResult<out T> {
data class Success<out T>(val data: T) : NetworkResult<T>()
data class Error(val message: String) : NetworkResult<Nothing>()
}
fun fetchUser(id: String): NetworkResult<User> {
return try {
NetworkResult.Success(api.getUser(id))
} catch (e: Exception) {
NetworkResult.Error("Failed: ${e.message}")
}
}
В примере sealed класс NetworkResult моделирует два состояния: успех с данными и ошибка с сообщением. Функция fetchUser возвращает результат в любом случае, вызывающий код обрабатывает обе ветки через when. Это исключает состояние, когда ошибка не обработана. Обработчик ошибок через sealed class — стандарт для Android-разработки в IT Sectr.
Result — встроенный тип Kotlin для представления результата операции, которая может завершиться ошибкой. Он принуждает обрабатывать success и failure через fold, getOrThrow или map. Result полезен в асинхронных цепочках (coroutines). Обработка ошибок с помощью Result — стандарт для мобильной разработки на Kotlin.
Either — функциональный тип из библиотеки Arrow, который позволяет вернуть значение одного из двух типов (Left — ошибка, Right — успех). В отличие от Result, Either может содержать любой user-defined тип ошибки. Для простых проектов достаточно встроенного Result, для сложных — Either из Arrow. Выбор инструмента для обработки ошибок зависит от сложности проекта.
Error Propagation — механизм, при котором ошибка пробрасывается вверх по стеку вызовов, пока не будет обработана. В Kotlin это происходит по умолчанию (unchecked exceptions). В Swift — только для функций, помеченных throws. В Result и Either ошибка не пробрасывается — она остаётся в типе, и вы обязаны её обработать. Это делает обработку ошибок в мобильных приложениях более безопасной.
| Параметр | iOS (Swift) | Android (Kotlin) |
|---|---|---|
| Базовый механизм | do-catch + throws | try-catch (expression) |
| Optional/Nullable | guard let, if-let, ?? | ?. let, elvis (?:) |
| Функциональный подход | Result (Swift 5+) | Result, Either (Arrow) |
| Моделирование ошибок | Enum: Error | Sealed class |
| Checked exceptions | Да (throws) | Нет (все unchecked) |
| Non-fatal | os_log, Crashlytics | Timber, Crashlytics |
Таблица показывает ключевые отличия. iOS требует явной декларации ошибок (throws), что делает код безопаснее, но более многословным. Android полагается на дисциплину разработчика. В IT Sectr мы используем sealed class для Android и throws для iOS — это best practice обеих платформ для обработки ошибок в мобильном приложении.
Crash reporting — система сбора и анализа крашей приложения. Crash reporting — неотъемлемая часть обработки ошибок в продакшене. Без неё вы узнаёте о проблемах от пользователей, что неприемлемо для продакшена. Два основных инструмента: Firebase Crashlytics (бесплатно) и Sentry (бесплатно для базового использования). Для обработки ошибок в мобильных приложениях обязательно внедряйте crash reporting с первого релиза.
Crashlytics — часть Firebase. Автоматически собирает краши, группирует их по стеку вызовов и показывает количество затронутых пользователей. Поддерживает логирование non-fatal ошибок через recordException(). Интеграция: добавьте SDK в build.gradle (Android) или Podfile (iOS). Crashlytics — лучший бесплатный инструмент для обработки ошибок на старте проекта.
Sentry — кросс-платформенная система мониторинга ошибок. В отличие от Crashlytics, Sentry даёт детальную трассировку (breadcrumbs), performance monitoring и поддержку React Native. Позволяет просматривать состояние приложения в момент ошибки. IT Sectr рекомендует Sentry для проектов, где нужен полный контроль над обработкой ошибок в мобильной разработке.
Error Boundary — React-компонент, который ловит JavaScript-ошибки в дочернем дереве и отображает fallback UI, предотвращая полное падение приложения. Error Boundary — ключевой компонент для обработки ошибок в React Native. Используйте error boundaries для критических экранов и навигации. Обработка ошибок в мобильных приложениях на React Native требует правильной настройки Error Boundary на верхнем уровне.
Error Boundary создаётся через componentDidCatch(error, errorInfo) или static getDerivedStateFromError(error). Он не ловит ошибки в асинхронном коде (setTimeout, requestAnimationFrame), серверном рендеринге или собственные ошибки (Native Modules). Для логирования используйте crash reporting SDK внутри componentDidCatch. Error Boundary — простой, но эффективный обработчик ошибок для UI-слоя.
Fatal error — это необработанное исключение, которое приводит к крашу приложения. Non-fatal error — это исключение, которое вы поймали и обработали, но оно указывает на проблему в коде. Non-fatal ошибки логируются через Crashlytics/Sentry и помогают найти баги до того, как они станут фатальными. И фатальные, и нефатальные ошибки требуют грамотной обработки ошибок в мобильной разработке.
Часто задаваемые вопросы
try-catch — это механизм языка для исключений. Result — это тип-обёртка, который принуждает обрабатывать ошибку на этапе компиляции. В IT Sectr мы предпочитаем Result для бизнес-логики и try-catch для работы с внешними системами. Оба подхода — часть общей обработки ошибок в Kotlin.
Error Boundary — это React-компонент, который отлавливает JavaScript-ошибки в дочернем дереве компонентов и показывает запасной UI вместо падения всего приложения. Он не ловит ошибки в асинхронном коде и серверном рендеринге. Error Boundary — важный элемент обработки ошибок в мобильных приложениях на React Native.
Crashlytics (Firebase) — лучший выбор для начала: бесплатно, простая интеграция, автоматическая группировка крашей. Sentry — для проектов, где нужна детальная трассировка ошибок и мониторинг производительности. Выбор инструмента для обработки ошибок зависит от бюджета и требований к мониторингу.
Fatal error — это краш приложения (uncaught exception). Non-fatal error — это исключение, которое вы поймали и обработали, но оно говорит о проблеме в коде. Non-fatal ошибки логируются отдельно и помогают находить баги до того, как они станут фатальными. Обработка ошибок в мобильном приложении должна включать мониторинг обоих типов.
guard let используется для раннего выхода из функции при отсутствии значения — это делает код более линейным и читаемым. if-let подходит, когда optional нужен внутри блока и не требуется выход из функции. guard let предпочтительнее для валидации входных параметров и является частью обработки ошибок в iOS.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.