Do-Catchとは:Swiftにおける構文とエラー処理

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

Do-Catchは、throwによってスローされた例外をキャッチし、対応するコードブロックを実行するSwift言語のエラー処理構文です。他の言語の従来のtry-catchとは異なり、Swiftではthrows修飾子を使用してエラーをスローできる関数を明示的にマークする必要があります。Swift.org、2026によると、Do-CatchはSwiftの主要なエラー処理メカニズムであり、型安全性を提供します。

重要ポイント

  • Do-Catchは、tryとthrowを含むブロックからエラーをキャッチするSwiftの構文です。
  • throwsは、関数がエラーをスローできることを示す関数マーカーです。
  • tryは、doブロック内でthrowing関数を呼び出すためのキーワードです。
  • catchは、型によるパターンマッチングを備えたエラー処理ブロックです。
  • try?try!は、エラーをnilに変換するかクラッシュを引き起こす代替形式です。

Do-Catchとは?

Do-Catchは、エラーをスローできるコードを実行するdoブロックと、そのエラーを処理する1つ以上のcatchブロックで構成されるSwiftの構文です。doブロックにはtryでマークされたthrowing関数の呼び出しが含まれ、catchブロックは型によってエラーをマッチングします。

SwiftはObjective-Cの例外とは異なる構造化エラー処理のモデルを実装しています。ここでのエラーはスタック巻き戻しを伴う例外ではなく、Errorプロトコルに準拠する値です。throwによるエラーのスローは、スタック巻き戻しのオーバーヘッドなしに最も近いcatchブロックに制御を移します。

Swiftの重要な特徴は明示的な処理です。コンパイラはtry、do-catch、または代替メカニズム(try?、try!)なしでthrowing関数の呼び出しを許可しません。これにより、エラーが見逃される状況が排除されます。

Swiftのエラーモデル:Errorプロトコルとthrowing関数

Swiftのエラー処理の中心にあるのはErrorプロトコルです。このプロトコルに準拠する任意の型はthrowによってスローできます。エラーは通常、Errorに準拠するenumとして定義されます。

Errorプロトコル

Errorは空の(マーカー)プロトコルです。メソッドの実装は必要なく、準拠のみが必要です。Swiftコンパイラは静的なチェックにErrorを使用します:throwsを持つ関数はErrorに準拠する値のみをスローできます。

Throwing関数

throwsでマークされた関数はtryとともに呼び出す必要があります。そのような関数内でthrowが発生すると、制御は呼び出し元のdo-catchに移ります。呼び出しチェーンのどこでもエラーが処理されない場合、エラーは上位レベルに伝播します。

swift
enum FileError: Error {
    case notFound
    case permissionDenied
    case corrupted(String)
}

func readFile(path: String) throws -> String {
    guard FileManager.default.fileExists(atPath: path) else {
        throw FileError.notFound
    }
    return try String(contentsOfFile: path)
}

Rethrows

rethrowsは、パラメータとしてthrowingクロージャを受け取る関数のための修飾子です。渡されたクロージャがエラーをスローしない場合、rethrows関数はtryなしで呼び出すことができます。これにより、throwingとnon-throwingの両方のクロージャと互換性のあるジェネリック高階関数を書くことができます。

Do-Catchの構文:複数のcatchブロック

Swiftは型ベースのエラーマッチングによる複数のcatchブロックをサポートしています。これはKotlinのwhenや型によるswitchと似ています:最初にマッチしたcatchが実行され、残りはスキップされます。

型によるマッチング

各catchブロックは特定のエラー型にマッチするパターンを含むことができます。Swiftはブロックを順番にチェックするため、より具体的な型は一般的な型の前に配置する必要があります。どのパターンもマッチしない場合、パターンのないcatchブロックが実行されます。

複数の型の処理

Do-Catchの型安全性により、各エラーを個別に処理したり、カンマ区切りのパターンマッチングを通じて1つのブロックで複数の型を組み合わせたりできます。これにより、Objective-Cに典型的だったif-elseチェーンが不要になります。Objective-Cでは、戻りコードまたはドメインとコードのチェックによるNSErrorを通じてエラー分析が行われていました。

Swiftは追加条件によるマッチングのためのcatch whereもサポートしています。たとえば、特定のコードやテキストでエラーをフィルタリングできます:catch URLError where error.code == .notConnectedToInternet。これにより、精度を維持しながらcatchブロックの数を減らせます。

throwing関数のデバッグのために、Swiftはエラーと例外の区別を提供します。Swiftのエラーはスタック巻き戻しを必要としない戻り値です。Objective-Cの例外(@try/@catch)はランタイムレベルで動作し、致命的な障害にのみ使用されます。Do-Catchは例外ではなくエラーを処理するため、予測可能で効率的です。

ライブラリやSDKを開発する際、throwing関数は公開契約の一部であることを覚えておくことが重要です。エラー型はシグネチャで指定されていないため、関数がスローする可能性のあるエラーをコメントやResult風のenumを通じて文書化してください。これにより、APIユーザーは実装を見ることなく正しいcatchブロックを書くことができます。

非同期プログラミングの文脈では、async/awaitを使用したDo-Catchがコールバック地獄の問題を解決します。以前のSwiftでは、非同期コードでのエラー処理には、completionハンドラーでのError?チェックを伴うネストされたクロージャが必要でした。async/awaitとDo-Catchを使用すると、非同期throwingコードは同期コードのように見え、各ステップでのエラー処理を含む複雑なリクエストチェーンの読み取りと保守が簡素化されます。

swift
do {
    let content = try readFile(path: "/data/config.json")
    process(content)
} catch FileError.notFound {
    createDefaultConfig()
} catch FileError.permissionDenied {
    requestAccess()
} catch FileError.corrupted(let detail) {
    logCorruption(detail)
} catch {
    print("不明なエラー: \(error)")
}

Tryのバリエーション:try、try?、try!とその使用時期

Swiftはthrowing関数を呼び出す3つの方法を提供します:trytry?try!。各オプションは特定のタスクを解決し、制限があります。

try — 標準呼び出し

tryはdoブロック内で使用され、エラーはcatchで処理されます。これがthrowing関数を呼び出す主要な方法です。コンパイラはtryがエラーをキャッチできるコンテキストにあることを要求します。

try? — Optionalへの変換

try?はthrowing関数の結果をOptionalに変換します。関数がエラーをスローした場合、try?はnilを返し、そうでなければ成功した値を持つOptionalを返します。エラーを無視できるが成功の指標が必要な呼び出しに便利です。

try! — 強制実行

try!はエラー処理を抑制します。throwing関数がエラーをスローした場合、アプリはランタイムエラーで終了します。try!は、エラーが絶対に不可能であると確信できる場合にのみ使用してください — たとえば、バンドルリソースの読み込み時など。

swift
// try? — エラーを無視、失敗時にnilを取得
if let data = try? Data(contentsOf: url) {
    processData(data)
}

// try! — エラーが絶対に不可能な場合のみ
let bundled = try! String(contentsOfFile: "Assets/default.txt")

// try — do-catchの標準オプション
do {
    let result = try performNetworkRequest()
    updateUI(result)
} catch {
    showError(error)
}

iOS開発におけるDo-Catch:実践例

Do-Catchは、システムAPIを扱うiOS開発で積極的に使用されています。典型的なシナリオを見てみましょう:ファイルシステム、Core Data、ネットワークリクエスト。

ファイルシステム

FileManagerの多くのメソッドはthrowingです。Do-Catchにより、ファイルの不存在、リソースのビジー状態、権限不足を適切に処理できます。

Codableを使用したネットワークリクエスト

JSONDecoderによるJSON解析はthrowing操作です。Do-Catchはデコードエラーとネットワーク障害を個別にキャッチし、ユーザーに正確なエラーメッセージを提供します。

swift
struct User: Codable {
    let id: Int
    let name: String
}

func fetchUser(id: Int) async throws -> User {
    let url = URL(string: "https://api.example.com/users/\(id)")!
    let (data, _) = try await URLSession.shared.data(from: url)
    return try JSONDecoder().decode(User.self, from: data)
}

// 処理付き呼び出し
do {
    let user = try await fetchUser(id: 42)
    showUser(user)
} catch let error as URLError {
    showNetworkAlert(error)
} catch let error as DecodingError {
    showParseError(error)
} catch {
    showGenericError(error)
}

Do-Catchのよくある間違い

特に他の言語から移行してきた開発者は、Do-Catchを使用する際に特徴的な間違いをよく犯します。最も一般的なものを見てみましょう。

  • tryの忘れ — tryなしでthrowing関数を呼び出すとコンパイルエラーになります。Swiftは暗黙的にエラーを無視することを許可しません。
  • 空のcatch — 処理のないcatchブロックはエラーを隠します。たとえ不可能に思えても、常にエラーをログ出力するか処理してください。
  • マッチングのないcatch — すべてのエラーに対する1つの汎用catchは型安全性の利点を失います。複数のブロックを使用して型ごとに処理を分けてください。
  • try!の過剰使用 — 本番コードでのtry!は予期しないクラッシュの原因です。バンドルリソースやテストにのみ使用してください。

よくある質問

SwiftのDo-Catchは他の言語のtry-catchとどう違うのですか?

Swiftでは、エラーはErrorプロトコルに準拠する値であり、スタック巻き戻しを伴う例外ではありません。throwing関数は明示的にthrowsでマークする必要があり、コンパイラは呼び出し時にtryを要求します — これによりコンパイル時に未処理のエラーが排除されます。

Do-Catchはasync/awaitと一緒に使用できますか?

はい、async関数もthrowsにでき、do-catchはそれらで機能します。非同期throwing関数の呼び出しには、doブロック内でtry awaitが必要です。これは非同期Swiftコードでエラーを処理する標準的な方法です。

do-catchなしでエラーを処理するには?

代替手段があります:try?はエラーをnilに変換し、try!はエラー時にクラッシュを引き起こし、rethrowsはクロージャからエラーを伝播できます。do-catchは明示的な処理の主要な方法であり続けます。

1つの関数が異なる型のエラーをスローできますか?

Swiftはスローされるエラーを型付けしません — 任意のthrowing関数はErrorに準拠する任意の型をスローできます。特定のエラー型によるcatchでのマッチングを通じて処理を分けてください。

すべてのエラーをカスタム型でラップすべきですか?

はい、それはベストプラクティスです。Errorに準拠するenumとしてAppErrorを定義し、システムエラーをドメインエラーに変換してください。これにより処理が統一され、アプリケーション層がシステムの詳細から分離されます。

まとめ

  • Do-Catchは、関数へのthrowsの必須マークと呼び出し時のtryを備えたSwiftのエラー処理構文です。
  • SwiftのエラーはErrorプロトコルに準拠する値であり、スタック巻き戻しを伴う例外ではなく、障害がない場合のオーバーヘッドはゼロです。
  • 複数のcatchブロックにより、switchと同様のパターンマッチングで異なるエラー型を個別に処理できます。
  • try?は単純なシナリオでエラーをnilに変換し、try!は保証された成功操作にのみ使用されるクラッシュリスクのある強制呼び出しです。
  • Do-Catchとasync/awaitは、try awaitを使用して非同期Swiftコードでエラーを処理する標準的な方法です。
  • 空のcatchブロックとtry!の過剰使用を避けてください — これらはエラーを隠し、本番環境で予期しないクラッシュを引き起こします。

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

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

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

こちらもお読みください