エラーハンドリングはモバイル開発者にとって基本的なスキルです。HackerOne (2025)によると、データ漏洩の62%は未処理の例外が原因で発生しています。適切なエラーハンドリングはクラッシュを防ぐだけでなく、ユーザーデータも保護します。iOS、Android、React Nativeのアプローチを見ていきましょう。
重要ポイント
エラーハンドリングはSwiftでは4つの主要なメカニズムに基づいています:do-catch、throws、guard let、if-letです。多くの言語とは異なり、Swiftはキャッチされない例外を許可しません — すべてのエラーは明示的に処理されるか、throwsで宣言されなければなりません。エラーハンドリングはモバイル開発にとって重要なスキルであり、アプリケーションの安定性に直接影響します。
do-catchはthrowsでマークされた関数を呼び出すための標準ブロックです。doの内部でtryとともに関数が呼び出され、エラーがスローされると制御がcatchに移ります。パターンマッチングにより異なるエラータイプを処理できます。エラーが処理されない場合、スタックを上に伝播します(Error Propagation)。iOSで効果的なエラーハンドリングを行うには、do-catchを主要なメカニズムとして使用してください。
Throwは関数シグネチャで宣言されます:func fetchData() throws -> Data。これは呼び出し元のコードがtry、try?、try!を介してエラーを処理しなければならないことを意味します。try?はエラーをnilに変換し、try!はエラー時にクラッシュを引き起こします(成功が確実な場合のみ使用してください)。throwによるエラーハンドリングはSwiftでは必須のプラクティスです。
Guard letは値がnilの場合に関数から早期に抜け出すための構文です。if-letとは異なり、guard letはelseブランチでexit(return、throw、break)を必要とします。これにより、ネストされたifブロックがなくなり、コードがよりフラットで読みやすくなります。optionalがnilにならない場合は、完全に確信がある場合のみforce unwrap(!)を使用してください。モバイルアプリでは、guard letはオプショナル値の処理時にクラッシュを回避するのに役立ちます。
Optional Chaining(user?.address?.city)やnil-coalescing(??)は、アンラップせずにoptionalを扱うためのシンタックスシュガーです。IT Sectrでは、API入力パラメータの検証にguard letを使用し、明示的なコメントなしでのforce unwrapを避けるようチームに徹底しています。各レベルのエラーハンドラが予期しない障害から保護します。
KotlinはAndroid開発の主要言語です。Javaからtry-catchを継承していますが、より安全な代替手段を追加しています:エルビス演算子、require、check、sealed classです。Kotlinのエラーハンドリングはこれらのメカニズムの組み合わせに基づいています。Swiftとは異なり、Kotlinはチェックされる例外の処理を必要としません(すべての例外はuncheckedです)。Androidのモバイルアプリケーションでのエラーハンドリングには、sealed classを主要なパターンとして使用してください。
Try-catchはKotlinでは式として機能します — 値を返します。val result = try { fetchData() } catch (e: Exception) { fallbackValue }。これによりコードが短縮されます。エルビス演算子(?:)はnullable型のnil-coalescingに類似しています:val name = user?.name ?: "Guest"。モバイルアプリケーションのエラーハンドリングでは、式としてのtry-catchが最も簡潔なアプローチです。
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 classのNetworkResultが2つの状態をモデル化しています:データを伴う成功とメッセージを伴うエラーです。fetchUser関数はどのような場合でも結果を返し、呼び出し元のコードはwhenを介して両方のブランチを処理します。これにより、未処理のエラーの可能性が排除されます。sealed classによるエラーハンドリングは、IT SectrのAndroid開発の標準です。
Resultは、失敗する可能性のある操作の結果を表すKotlinの組み込み型です。fold、getOrThrow、mapを介して成功と失敗の処理を強制します。Resultは非同期チェーン(coroutines)で有用です。Resultによるエラーハンドリングは、Kotlinでのモバイル開発の標準です。
EitherはArrowライブラリの関数型で、2つの型のいずれかの値を返すことを可能にします(Left — エラー、Right — 成功)。Resultとは異なり、Eitherはユーザー定義の任意のエラー型を含めることができます。単純なプロジェクトでは組み込みのResultで十分です。複雑なプロジェクトではArrowのEitherを使用してください。エラーハンドリングツールの選択はプロジェクトの複雑さに依存します。
エラーの伝播は、エラーが処理されるまでコールスタックを上に伝播するメカニズムです。Kotlinではこれがデフォルトで発生します(unchecked例外)。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 |
| チェックされる例外 | あり(throws) | なし(すべてunchecked) |
| Non-fatal | os_log、Crashlytics | Timber、Crashlytics |
表は主要な違いを示しています。iOSは明示的なエラー宣言(throws)を必要とし、コードはより安全ですが冗長になります。Androidは開発者の規律に依存します。IT Sectrでは、Androidにはsealed class、iOSにはthrowsを使用しています — これはモバイルアプリケーションのエラーハンドリングにおける両プラットフォームのベストプラクティスです。
クラッシュレポーティングはアプリケーションのクラッシュを収集・分析するシステムです。クラッシュレポーティングは本番環境でのエラーハンドリングに不可欠な部分です。これなしでは、ユーザーから問題を知ることになり、本番環境では許容できません。2つの主要ツール:Firebase Crashlytics(無料)とSentry(基本使用は無料)です。モバイルアプリケーションのエラーハンドリングでは、最初のリリースから必ずクラッシュレポーティングを実装してください。
CrashlyticsはFirebaseの一部です。クラッシュを自動的に収集し、コールスタックでグループ化し、影響を受けたユーザー数を表示します。recordException()を介して非致命的エラーのログ記録をサポートします。統合:build.gradle(Android)またはPodfile(iOS)にSDKを追加します。Crashlyticsはプロジェクト開始時におけるエラーハンドリングに最適な無料ツールです。
Sentryはクロスプラットフォームのエラー監視システムです。Crashlyticsとは異なり、Sentryは詳細なトレーシング(breadcrumbs)、パフォーマンスモニタリング、React Nativeのサポートを提供します。エラー発生時のアプリケーション状態を表示できます。IT Sectrは、モバイル開発におけるエラーハンドリングを完全に制御する必要があるプロジェクトにSentryを推奨します。
Error Boundaryは、子コンポーネントツリーでのJavaScriptエラーをキャッチし、フォールバックUIを表示してアプリ全体のクラッシュを防ぐReactコンポーネントです。Error BoundaryはReact Nativeのエラーハンドリングにおける重要なコンポーネントです。重要な画面やナビゲーションにはerror boundariesを使用してください。React Nativeのモバイルアプリケーションにおけるエラーハンドリングには、トップレベルでの適切なError Boundaryのセットアップが必要です。
Error BoundaryはcomponentDidCatch(error, errorInfo)またはstatic getDerivedStateFromError(error)を介して作成されます。非同期コード(setTimeout、requestAnimationFrame)、サーバーサイドレンダリング、ネイティブエラー(Native Modules)のエラーはキャッチしません。ログ記録には、componentDidCatch内でクラッシュレポーティングSDKを使用してください。Error BoundaryはUIレイヤーのためのシンプルでありながら効果的なエラーハンドラです。
致命的エラーは、アプリケーションのクラッシュを引き起こす未処理の例外です。非致命的エラーは、キャッチして処理した例外ですが、コードに問題があることを示します。非致命的エラーはCrashlytics/Sentryを介してログ記録され、致命的になる前にバグを発見するのに役立ちます。致命的エラーと非致命的エラーの両方に、モバイル開発における適切なエラーハンドリングが必要です。
よくある質問
try-catchは例外のための言語メカニズムです。Resultはコンパイル時にエラーハンドリングを強制するラッパー型です。IT Sectrでは、ビジネスロジックにはResult、外部システムとの連携にはtry-catchを好んで使用しています。どちらのアプローチもKotlinの一般的なエラーハンドリングの一部です。
Error Boundaryは、子コンポーネントツリーでのJavaScriptエラーをキャッチし、アプリ全体をクラッシュさせる代わりにフォールバックUIを表示するReactコンポーネントです。非同期コードやサーバーサイドレンダリングのエラーはキャッチしません。Error BoundaryはReact Nativeのモバイルアプリケーションにおけるエラーハンドリングの重要な要素です。
Crashlytics(Firebase)は開始に最適な選択肢です:無料、簡単な統合、自動クラッシュグループ化。Sentryは詳細なエラートレーシングとパフォーマンスモニタリングが必要なプロジェクト向けです。エラーハンドリングツールの選択は、予算と監視要件に依存します。
致命的エラーはアプリケーションのクラッシュ(キャッチされなかった例外)です。非致命的エラーはキャッチして処理した例外ですが、コードに問題があることを示します。非致命的エラーは個別にログ記録され、致命的になる前にバグを発見するのに役立ちます。モバイルアプリケーションのエラーハンドリングには、両方のタイプの監視を含める必要があります。
guard letは値がない場合に関数から早期に抜け出すために使用します — これによりコードがより直線的で読みやすくなります。if-letはブロック内でoptionalが必要で関数からの抜け出しが必要ない場合に適しています。guard letは入力パラメータの検証に推奨され、iOSのエラーハンドリングの一部です。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。