モバイル開発におけるエラーハンドリング:概要、テクニック、整理方法

著者: IT Sectr 公開日: 2026-05-23 読了時間: 11 分

エラーハンドリングはモバイル開発者にとって基本的なスキルです。HackerOne (2025)によると、データ漏洩の62%は未処理の例外が原因で発生しています。適切なエラーハンドリングはクラッシュを防ぐだけでなく、ユーザーデータも保護します。iOS、Android、React Nativeのアプローチを見ていきましょう。

重要ポイント

  • iOSはエラーハンドリングにdo-catch、throw、guard let、if-letを使用します。Swiftは言語レベルで未処理の例外を許可しません。
  • Android/Kotlinはtry-catch、エルビス演算子、sealed class、Result型を提供します。Sealed classはエラーステートのモデリングに強力なツールです。
  • KotlinのResultや関数型ライブラリのEitherは、コンパイル時にエラーハンドリングを強制し、コードをより信頼性の高いものにします。
  • Crash Reporting(Crashlytics、Sentry)は本番環境では必須のツールです。これなしではユーザーからのみバグを知ることになります。
  • React NativeのError BoundaryはJavaScriptエラーによるアプリ全体のクラッシュを防ぎます。ルートコンポーネントに使用してください。

iOSのエラーハンドリング:Do-Catch、Throw、Guard Let

エラーハンドリングはSwiftでは4つの主要なメカニズムに基づいています:do-catch、throws、guard let、if-letです。多くの言語とは異なり、Swiftはキャッチされない例外を許可しません — すべてのエラーは明示的に処理されるか、throwsで宣言されなければなりません。エラーハンドリングはモバイル開発にとって重要なスキルであり、アプリケーションの安定性に直接影響します。

Do-CatchとThrow

do-catchはthrowsでマークされた関数を呼び出すための標準ブロックです。doの内部でtryとともに関数が呼び出され、エラーがスローされると制御がcatchに移ります。パターンマッチングにより異なるエラータイプを処理できます。エラーが処理されない場合、スタックを上に伝播します(Error Propagation)。iOSで効果的なエラーハンドリングを行うには、do-catchを主要なメカニズムとして使用してください。

Throwは関数シグネチャで宣言されます:func fetchData() throws -> Data。これは呼び出し元のコードがtry、try?、try!を介してエラーを処理しなければならないことを意味します。try?はエラーをnilに変換し、try!はエラー時にクラッシュを引き起こします(成功が確実な場合のみ使用してください)。throwによるエラーハンドリングはSwiftでは必須のプラクティスです。

Optional/NullableとGuard Let

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を避けるようチームに徹底しています。各レベルのエラーハンドラが予期しない障害から保護します。

Androidのエラーハンドリング:Try-Catch、Elvis、Sealed Class

KotlinはAndroid開発の主要言語です。Javaからtry-catchを継承していますが、より安全な代替手段を追加しています:エルビス演算子、require、check、sealed classです。Kotlinのエラーハンドリングはこれらのメカニズムの組み合わせに基づいています。Swiftとは異なり、Kotlinはチェックされる例外の処理を必要としません(すべての例外はuncheckedです)。Androidのモバイルアプリケーションでのエラーハンドリングには、sealed classを主要なパターンとして使用してください。

Try-Catchとエルビス演算子

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によるエラーハンドリングは、どの状態も未処理のままにならないことを保証します。

kotlin
// 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開発の標準です。

Kotlinのエラーハンドリング:ResultとEither

Resultは、失敗する可能性のある操作の結果を表すKotlinの組み込み型です。fold、getOrThrow、mapを介して成功と失敗の処理を強制します。Resultは非同期チェーン(coroutines)で有用です。Resultによるエラーハンドリングは、Kotlinでのモバイル開発の標準です。

Result vs Either

EitherはArrowライブラリの関数型で、2つの型のいずれかの値を返すことを可能にします(Left — エラー、Right — 成功)。Resultとは異なり、Eitherはユーザー定義の任意のエラー型を含めることができます。単純なプロジェクトでは組み込みのResultで十分です。複雑なプロジェクトではArrowのEitherを使用してください。エラーハンドリングツールの選択はプロジェクトの複雑さに依存します。

エラーの伝播

エラーの伝播は、エラーが処理されるまでコールスタックを上に伝播するメカニズムです。Kotlinではこれがデフォルトで発生します(unchecked例外)。Swiftでは、throwsでマークされた関数にのみ適用されます。ResultとEitherでは、エラーは伝播せず — 型内に留まり、処理する必要があります。これにより、モバイルアプリケーションのエラーハンドリングがより安全になります。

パラメータ iOS(Swift) Android(Kotlin)
基本メカニズムdo-catch + throwstry-catch(expression)
Optional/Nullableguard let、if-let、???. let、elvis(?:)
関数型アプローチResult(Swift 5+)Result、Either(Arrow)
エラーモデリングEnum: ErrorSealed class
チェックされる例外あり(throws)なし(すべてunchecked)
Non-fatalos_log、CrashlyticsTimber、Crashlytics

表は主要な違いを示しています。iOSは明示的なエラー宣言(throws)を必要とし、コードはより安全ですが冗長になります。Androidは開発者の規律に依存します。IT Sectrでは、Androidにはsealed class、iOSにはthrowsを使用しています — これはモバイルアプリケーションのエラーハンドリングにおける両プラットフォームのベストプラクティスです。

クラッシュレポーティング:CrashlyticsとSentry

クラッシュレポーティングはアプリケーションのクラッシュを収集・分析するシステムです。クラッシュレポーティングは本番環境でのエラーハンドリングに不可欠な部分です。これなしでは、ユーザーから問題を知ることになり、本番環境では許容できません。2つの主要ツール:Firebase Crashlytics(無料)とSentry(基本使用は無料)です。モバイルアプリケーションのエラーハンドリングでは、最初のリリースから必ずクラッシュレポーティングを実装してください。

Firebase Crashlytics

CrashlyticsはFirebaseの一部です。クラッシュを自動的に収集し、コールスタックでグループ化し、影響を受けたユーザー数を表示します。recordException()を介して非致命的エラーのログ記録をサポートします。統合:build.gradle(Android)またはPodfile(iOS)にSDKを追加します。Crashlyticsはプロジェクト開始時におけるエラーハンドリングに最適な無料ツールです。

Sentry

Sentryはクロスプラットフォームのエラー監視システムです。Crashlyticsとは異なり、Sentryは詳細なトレーシング(breadcrumbs)、パフォーマンスモニタリング、React Nativeのサポートを提供します。エラー発生時のアプリケーション状態を表示できます。IT Sectrは、モバイル開発におけるエラーハンドリングを完全に制御する必要があるプロジェクトにSentryを推奨します。

React NativeのError Boundary

Error Boundaryは、子コンポーネントツリーでのJavaScriptエラーをキャッチし、フォールバックUIを表示してアプリ全体のクラッシュを防ぐReactコンポーネントです。Error BoundaryはReact Nativeのエラーハンドリングにおける重要なコンポーネントです。重要な画面やナビゲーションにはerror boundariesを使用してください。React Nativeのモバイルアプリケーションにおけるエラーハンドリングには、トップレベルでの適切なError Boundaryのセットアップが必要です。

Error Boundaryの実装

Error BoundaryはcomponentDidCatch(error, errorInfo)またはstatic getDerivedStateFromError(error)を介して作成されます。非同期コード(setTimeout、requestAnimationFrame)、サーバーサイドレンダリング、ネイティブエラー(Native Modules)のエラーはキャッチしません。ログ記録には、componentDidCatch内でクラッシュレポーティングSDKを使用してください。Error BoundaryはUIレイヤーのためのシンプルでありながら効果的なエラーハンドラです。

致命的エラーと非致命的エラー

致命的エラーは、アプリケーションのクラッシュを引き起こす未処理の例外です。非致命的エラーは、キャッチして処理した例外ですが、コードに問題があることを示します。非致命的エラーはCrashlytics/Sentryを介してログ記録され、致命的になる前にバグを発見するのに役立ちます。致命的エラーと非致命的エラーの両方に、モバイル開発における適切なエラーハンドリングが必要です。

よくある質問

Kotlinのtry-catchとResultの違いは何ですか?

try-catchは例外のための言語メカニズムです。Resultはコンパイル時にエラーハンドリングを強制するラッパー型です。IT Sectrでは、ビジネスロジックにはResult、外部システムとの連携にはtry-catchを好んで使用しています。どちらのアプローチもKotlinの一般的なエラーハンドリングの一部です。

React NativeのError Boundaryとは何ですか?

Error Boundaryは、子コンポーネントツリーでのJavaScriptエラーをキャッチし、アプリ全体をクラッシュさせる代わりにフォールバックUIを表示するReactコンポーネントです。非同期コードやサーバーサイドレンダリングのエラーはキャッチしません。Error BoundaryはReact Nativeのモバイルアプリケーションにおけるエラーハンドリングの重要な要素です。

新しいプロジェクトにはCrashlyticsとSentryのどちらを使うべきですか?

Crashlytics(Firebase)は開始に最適な選択肢です:無料、簡単な統合、自動クラッシュグループ化。Sentryは詳細なエラートレーシングとパフォーマンスモニタリングが必要なプロジェクト向けです。エラーハンドリングツールの選択は、予算と監視要件に依存します。

非致命的エラーとは何ですか?致命的エラーとの違いは?

致命的エラーはアプリケーションのクラッシュ(キャッチされなかった例外)です。非致命的エラーはキャッチして処理した例外ですが、コードに問題があることを示します。非致命的エラーは個別にログ記録され、致命的になる前にバグを発見するのに役立ちます。モバイルアプリケーションのエラーハンドリングには、両方のタイプの監視を含める必要があります。

Swiftでif-letの代わりにguard letを使うべき時は?

guard letは値がない場合に関数から早期に抜け出すために使用します — これによりコードがより直線的で読みやすくなります。if-letはブロック内でoptionalが必要で関数からの抜け出しが必要ない場合に適しています。guard letは入力パラメータの検証に推奨され、iOSのエラーハンドリングの一部です。

まとめ

  • iOSはdo-catch、throws、guard letを使用します — すべてのエラーは関数シグネチャで宣言されなければなりません。iOSのエラーハンドリングには明示的な宣言が必要です。
  • Android/Kotlinは式としてのtry-catch、エルビス演算子、エラーモデリングのためのsealed classを提供します。Androidのエラーハンドリングはより柔軟ですが、規律が必要です。
  • Sealed classとResultはKotlinでの関数型エラーハンドリングのベストプラクティスです。未処理の状態を排除します。
  • クラッシュレポーティング(Crashlytics、Sentry)は本番環境で必須です。Crashlyticsから始め、プロジェクトの成長に伴ってSentryに移行してください。監視なしではモバイルアプリケーションのエラーハンドリングは不可能です。
  • React NativeのError BoundaryはUI全体のクラッシュを防ぎます。ナビゲーションの最上位レベルで使用してください。
  • 非致命的エラーは致命的エラーと同様に重要です — アプリのクラッシュ前に問題を示します。エラーハンドラは両方のタイプをログ記録する必要があります。
  • Global Exception Handlerは最後の防御線です。Thread.setDefaultUncaughtExceptionHandler(Android)またはNSSetUncaughtExceptionHandler(iOS)を実装して、すべてのキャッチされなかったエラーをログ記録してください。

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談