Error Handling エラーの処理

Error handling is the process of responding to and recovering from error conditions in your program. Swift provides first-class support for throwing, catching, propagating, and manipulating recoverable errors at runtime. エラー処理は、あなたのプログラムにおいてエラー状態へ応答してそこから復旧する過程です。スウィフトは、回復可能なエラーのスロー、キャッチ、伝達、そして取り扱いに対してファーストクラスのサポートを提供します。

Some operations aren’t guaranteed to always complete execution or produce a useful output. Optionals are used to represent the absence of a value, but when an operation fails, it’s often useful to understand what caused the failure, so that your code can respond accordingly. いくつかの操作は、常に実行を完了することや役に立つ出力を生成することを保証されません。オプショナルは、ある値の欠如を表すために使われます、しかしある操作が失敗する時、何がその失敗をもたらしたのか理解するのはしばしば役に立ちます、それであなたのコードはそれに適切に応答することができます。

As an example, consider the task of reading and processing data from a file on disk. There are a number of ways this task can fail, including the file not existing at the specified path, the file not having read permissions, or the file not being encoded in a compatible format. Distinguishing among these different situations allows a program to resolve some errors and to communicate to the user any errors it can’t resolve. ひとつの例として、ディスク上のファイルからデータを読み込んで処理する作業を考えてみてください。この作業が失敗するたくさんの道筋があります、そのファイルが指定したパスで存在しない、ファイルが読み出し権限を持っていない、またはファイルが互換性のある形式で符号化されていないことを含めて。これらの異なった状況を区別することは、プログラムにいくらかのエラーを解消すること、そしてなんらかのそれが解消できないエラーを利用者に伝えることを可能にします。

Note 注意

Error handling in Swift interoperates with error handling patterns that use the NSError class in Cocoa and Objective-C. For more information about this class, see Handling Cocoa Errors in Swift. スウィフトでのエラー処理は、CocoaとObjective-CでのNSErrorクラスを使うエラー処理パターンと相互運用性があります。このクラスについてのさらなる情報として、CocoaエラーをSwiftにおいて処理するを見てください。

Representing and Throwing Errors エラーの表現とスロー

In Swift, errors are represented by values of types that conform to the Error protocol. This empty protocol indicates that a type can be used for error handling. スウィフトでは、エラーはErrorプロトコルに準拠する型の値によって表されます。この空のプロトコルは、ある型がエラー処理のために使われることができるのを示します。

Swift enumerations are particularly well suited to modeling a group of related error conditions, with associated values allowing for additional information about the nature of an error to be communicated. For example, here’s how you might represent the error conditions of operating a vending machine inside a game: スウィフト列挙は、あるエラーの性質についての追加情報が通信されるのを想定した関連値を含め、関係のあるエラー状況のグループを作るのにうってつけです。例えば、ここにあなたが表すかもしれないあるゲーム内の自動販売機操作のエラー状況がどのようなものかがあります:

  1. enum VendingMachineError: Error {
  2. case invalidSelection
  3. case insufficientFunds(coinsNeeded: Int)
  4. case outOfStock
  5. }

Throwing an error lets you indicate that something unexpected happened and the normal flow of execution can’t continue. You use a throw statement to throw an error. For example, the following code throws an error to indicate that five additional coins are needed by the vending machine: エラーのスローがあなたに示すのは、何か予期せぬことが起こった、そして通常の実行の流れは続けることができないということです。あなたはthrow文を使ってエラーをスローします。例えば、以下のコードはあるエラーをスローして、5つの追加のコインが自動販売機に必要とされることを示します。

  1. throw VendingMachineError.insufficientFunds(coinsNeeded: 5)

Handling Errors エラーを処理する

When an error is thrown, some surrounding piece of code must be responsible for handling the error—for example, by correcting the problem, trying an alternative approach, or informing the user of the failure. あるエラーがスローされるとき、なかには周囲のコード部分がエラーを処理することに対して責任を持たなければならないこともあります ― 例えば、問題を訂正すること、代わりの取り組みを試みること、または失敗をユーザに知らせることによって。

There are four ways to handle errors in Swift. You can propagate the error from a function to the code that calls that function, handle the error using a do-catch statement, handle the error as an optional value, or assert that the error will not occur. Each approach is described in a section below. 4つの方法がエラーを取り扱うためにスウィフトにはあります。あなたは、エラーを関数からその関数を呼び出しているコードに伝えて、そのエラーをdo-catch文を使って取り扱う、エラーをオプショナルとして取り扱う、またはそのエラーは起こらないことを表明することができます。各取り組みは、以下の節で記述されます。

When a function throws an error, it changes the flow of your program, so it’s important that you can quickly identify places in your code that can throw errors. To identify these places in your code, write the try keyword—or the try? or try! variation—before a piece of code that calls a function, method, or initializer that can throw an error. These keywords are described in the sections below. ある関数がエラーをスローするとき、それはあなたのプログラムの流れを変えます、そのため重要なのは、あなたがすばやくあなたのコードの中のエラーをスローできる場所を識別することです。これらの場所をあなたのコードの中で識別するには、tryキーワードを ― またはその変種try?またはtry!を ― エラーをスローできる関数、メソッド、またはイニシャライザを呼び出すコードの前の場所に書いてください。これらのキーワードは、以下の節で解説されます。

Note 注意

Error handling in Swift resembles exception handling in other languages, with the use of the try, catch and throw keywords. Unlike exception handling in many languages—including Objective-C—error handling in Swift doesn’t involve unwinding the call stack, a process that can be computationally expensive. As such, the performance characteristics of a throw statement are comparable to those of a return statement. スウィフトにおけるエラー処理は、trycatch、そしてthrowキーワードの使用とともに、他の言語での例外処理に似ています。多くの言語 ― Objective-Cを含めて ― での例外処理と違い、スウィフトにおけるエラー処理はコールスタック、計算的に高くつく可能性がある処理、の巻き戻し(アンワインド)を必要としません。throw文のいろいろな性能特徴は、それ自体としては、return文のそれと同程度です。

Propagating Errors Using Throwing Functions スロー関数を使ってエラーを伝える

To indicate that a function, method, or initializer can throw an error, you write the throws keyword in the function’s declaration after its parameters. A function marked with throws is called a throwing function. If the function specifies a return type, you write the throws keyword before the return arrow (->). エラーをスローすることのできる関数、メソッド、またはイニシャライザを指し示すために、あなたはthrowsキーワードを関数の定義においてそれのパラメータの後に書きます。throwsで印された関数は、スロー関数と呼ばれます。その関数が戻り型を指定するならば、あなたはthrowsキーワードを戻り矢印(->)の前に書きます。

  1. func canThrowErrors() throws -> String
  2. func cannotThrowErrors() -> String

A throwing function propagates errors that are thrown inside of it to the scope from which it’s called. スロー関数は、それの内部でスローされるエラーを、そこからそれが呼び出されるスコープへと伝えます。

Note 注意

Only throwing functions can propagate errors. Any errors thrown inside a nonthrowing function must be handled inside the function. スロー関数だけがエラーを伝えることができます。スローしない関数の内部でスローされるどんなエラーも、その関数の内部で取り扱われなければなりません。

In the example below, the VendingMachine class has a vend(itemNamed:) method that throws an appropriate VendingMachineError if the requested item isn’t available, is out of stock, or has a cost that exceeds the current deposited amount: 下の例において、VendingMachineクラスはvend(itemNamed:)メソッドを持ちます、それは、要求された項目が利用可能でない、在庫切れ、または現在預け入れされた総額を超える価格を持つならば対応するVendingMachineErrorをスローします:

  1. struct Item {
  2. var price: Int
  3. var count: Int
  4. }
  5. class VendingMachine {
  6. var inventory = [
  7. "Candy Bar": Item(price: 12, count: 7),
  8. "Chips": Item(price: 10, count: 4),
  9. "Pretzels": Item(price: 7, count: 11)
  10. ]
  11. var coinsDeposited = 0
  12. func vend(itemNamed name: String) throws {
  13. guard let item = inventory[name] else {
  14. throw VendingMachineError.invalidSelection
  15. }
  16. guard item.count > 0 else {
  17. throw VendingMachineError.outOfStock
  18. }
  19. guard item.price <= coinsDeposited else {
  20. throw VendingMachineError.insufficientFunds(coinsNeeded: item.price - coinsDeposited)
  21. }
  22. coinsDeposited -= item.price
  23. var newItem = item
  24. newItem.count -= 1
  25. inventory[name] = newItem
  26. print("Dispensing \(name)")
  27. }
  28. }

The implementation of the vend(itemNamed:) method uses guard statements to exit the method early and throw appropriate errors if any of the requirements for purchasing a snack aren’t met. Because a throw statement immediately transfers program control, an item will be vended only if all of these requirements are met. vend(itemNamed:)メソッドの実装はguard文を使って、購入スナックに必要な何かが満たされないならば早めにそのメソッドを終了して対応するエラーをスローします。throw文が直ちにプログラム制御を移すので、これらの必要なものすべてが満たされる場合にのみ項目は販売されることになります。

Because the vend(itemNamed:) method propagates any errors it throws, any code that calls this method must either handle the errors—using a do-catch statement, try?, or try!—or continue to propagate them. For example, the buyFavoriteSnack(person:vendingMachine:) in the example below is also a throwing function, and any errors that the vend(itemNamed:) method throws will propagate up to the point where the buyFavoriteSnack(person:vendingMachine:) function is called. このvend(itemNamed:)メソッドはそれがスローするどんなエラーも伝達するので、このメソッドを呼び出す何らかのコードは、それらのエラーを取り扱うか ― do-catch文、try?、またはtry!を使って ― またはそれらの伝達を続けるか、どちらかをしなければなりません。たとえば、下の例のbuyFavoriteSnack(person:vendingMachine:)もまたスロー関数です、そしてvend(itemNamed:)メソッドがスローするあらゆるエラーは、buyFavoriteSnack(person:vendingMachine:)関数が呼び出される地点へとさかのぼり伝えられます。

  1. let favoriteSnacks = [
  2. "Alice": "Chips",
  3. "Bob": "Licorice",
  4. "Eve": "Pretzels",
  5. ]
  6. func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws {
  7. let snackName = favoriteSnacks[person] ?? "Candy Bar"
  8. try vendingMachine.vend(itemNamed: snackName)
  9. }

In this example, the buyFavoriteSnack(person: vendingMachine:) function looks up a given person’s favorite snack and tries to buy it for them by calling the vend(itemNamed:) method. Because the vend(itemNamed:) method can throw an error, it’s called with the try keyword in front of it. この例において、buyFavoriteSnack(person: vendingMachine:)関数は指定された個人のお気に入りのスナックを探してそれを彼らのために仕入れることをvend(itemNamed:)メソッドを呼ぶことによって試みます。vend(itemNamed:)メソッドはエラーをスローできることから、それはそれの前のtryキーワードとともに呼び出されます。

Throwing initializers can propagate errors in the same way as throwing functions. For example, the initializer for the PurchasedSnack structure in the listing below calls a throwing function as part of the initialization process, and it handles any errors that it encounters by propagating them to its caller. スローするイニシャライザは、スローする関数と同じ方法でエラーを伝達できます。例えば、以下のコード出力のPurchasedSnack構造体のためのイニシャライザは、スロー関数を初期化処理の一部として呼び出します、そしてそれは、それが遭遇するどんなエラーもそれの呼び出し側にそれらを伝達することによって取り扱います。

  1. struct PurchasedSnack {
  2. let name: String
  3. init(name: String, vendingMachine: VendingMachine) throws {
  4. try vendingMachine.vend(itemNamed: name)
  5. self.name = name
  6. }
  7. }

Handling Errors Using Do-Catch do-catchを使ってエラーを処理する

You use a do-catch statement to handle errors by running a block of code. If an error is thrown by the code in the do clause, it’s matched against the catch clauses to determine which one of them can handle the error. あなたは、あるコードの塊を実行することによってエラーを処理するために、do-catch文を使います。あるエラーがdo節の中にあるコードによってスローされるならば、それはcatch節と照合されて、それらの1つがそのエラーを処理できると決定されます。

Here is the general form of a do-catch statement: ここにdo-catch文の一般的な形式があります:

  1. do {
  2. try expression
  3. statements
  4. } catch pattern 1 {
  5. statements
  6. } catch pattern 2 where condition {
  7. statements
  8. } catch pattern 3, pattern 4 where condition {
  9. statements
  10. } catch {
  11. statements
  12. }

You write a pattern after catch to indicate what errors that clause can handle. If a catch clause doesn’t have a pattern, the clause matches any error and binds the error to a local constant named error. For more information about pattern matching, see Patterns. あなたは、catchの後にあるパターンを書いてどんなエラーをその節が取り扱えるかを指し示します。catch節がパターンを持たないならば、その節はあらゆるエラーにマッチします、そしてそのエラーをerrorと名前を付けられるローカル定数に束縛します。パターンマッチングについての更なる情報として、パターンを見てください。

For example, the following code matches against all three cases of the VendingMachineError enumeration. 例えば、以下のコードはVendingMachineError列挙の3つのケース節すべてに対して適合します。

  1. var vendingMachine = VendingMachine()
  2. vendingMachine.coinsDeposited = 8
  3. do {
  4. try buyFavoriteSnack(person: "Alice", vendingMachine: vendingMachine)
  5. print("Success! Yum.")
  6. } catch VendingMachineError.invalidSelection {
  7. print("Invalid Selection.")
  8. } catch VendingMachineError.outOfStock {
  9. print("Out of Stock.")
  10. } catch VendingMachineError.insufficientFunds(let coinsNeeded) {
  11. print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.")
  12. } catch {
  13. print("Unexpected error: \(error).")
  14. }
  15. // Prints "Insufficient funds. Please insert an additional 2 coins."(「金額が不足しています。さらに2コイン入れてください。」を出力します)

In the above example, the buyFavoriteSnack(person:vendingMachine:) function is called in a try expression, because it can throw an error. If an error is thrown, execution immediately transfers to the catch clauses, which decide whether to allow propagation to continue. If no pattern is matched, the error gets caught by the final catch clause and is bound to a local error constant. If no error is thrown, the remaining statements in the do statement are executed. 上の例において、buyFavoriteSnack(person:vendingMachine:)関数はtry式の中で呼び出されます、それがエラーをスローできるからです。エラーがスローされるならば、実行は直ちにcatch節に移ります、それは伝達を継続させるかどうか結論を下します。パターンが適合することが全く無いならば、エラーは最後のcatch節によってキャッチされて、あるローカルerror定数に束縛されます。エラーがスローされることが全く無いならば、do文に残っている文が遂行されます。

The catch clauses don’t have to handle every possible error that the code in the do clause can throw. If none of the catch clauses handle the error, the error propagates to the surrounding scope. However, the propagated error must be handled by some surrounding scope. In a nonthrowing function, an enclosing do-catch statement must handle the error. In a throwing function, either an enclosing do-catch statement or the caller must handle the error. If the error propagates to the top-level scope without being handled, you’ll get a runtime error. catch節は、do節の中のコードがスロー可能なすべての起こりうるエラーを取り扱う必要はありません。どのcatch節もエラーを処理しないならば、エラーは周囲のスコープへと伝えられます。しかしながら、伝えられるエラーは周囲のスコープの何れかによって処理される必要があります。非スロー関数では、取り囲んでいるdo-catch文がエラーを処理しなければなりません。スロー関数では、取り囲んでいるdo-catch文または呼び出し側のどちらかがエラーを処理しなければなりません。エラーが取り扱われることなくトップレベルスコープに伝わるならば、あなたは実行時エラーを得るでしょう。

For example, the above example can be written so any error that isn’t a VendingMachineError is instead caught by the calling function: 例えば、上の例はVendingMachineErrorでないあらゆるエラーが、呼び出し側の関数によって代わりにキャッチされるように書かれることができます:

  1. func nourish(with item: String) throws {
  2. do {
  3. try vendingMachine.vend(itemNamed: item)
  4. } catch is VendingMachineError {
  5. print("Couldn't buy that from the vending machine.")
  6. }
  7. }
  8. do {
  9. try nourish(with: "Beet-Flavored Chips")
  10. } catch {
  11. print("Unexpected non-vending-machine-related error: \(error)")
  12. }
  13. // Prints "Couldn't buy that from the vending machine."

In the nourish(with:) function, if vend(itemNamed:) throws an error that’s one of the cases of the VendingMachineError enumeration, nourish(with:) handles the error by printing a message. Otherwise, nourish(with:) propagates the error to its call site. The error is then caught by the general catch clause. nourish(with:)関数において、vend(itemNamed:)VendingMachineError列挙のケース節の1つであるエラーをスローするならば、nourish(with:)はそのエラーをメッセージを出力することによって取り扱います。そうでなければ、nourish(with:)はそのエラーをそれの呼出地点へと伝達します。エラーは、それから一般的なcatch節によってキャッチされます。

Another way to catch several related errors is to list them after catch, separated by commas. For example: いくつかの関連したエラーをキャッチする別の方法は、それらをcatchの後に、コンマで区切って列記することになります。例えば:

  1. func eat(item: String) throws {
  2. do {
  3. try vendingMachine.vend(itemNamed: item)
  4. } catch VendingMachineError.invalidSelection, VendingMachineError.insufficientFunds, VendingMachineError.outOfStock {
  5. print("Invalid selection, out of stock, or not enough money.")
  6. }
  7. }

The eat(item:) function lists the vending machine errors to catch, and its error text corresponds to the items in that list. If any of the three listed errors are thrown, this catch clause handles them by printing a message. Any other errors are propagated to the surrounding scope, including any vending-machine errors that might be added later. eat(item:)関数は、自動販売機エラーそれらをリストしてキャッチします、そしてそれのエラーテキストをそのリストの中の項目と結び付けます。3つのリストされたエラーのどれかがスローされるならば、このcatch節はそれらをあるメッセージを出力することによって取り扱います。何らかの他のエラーは、周囲のスコープに伝播されます、後で加えられるかもしれないあらゆる自動販売機エラーを含めて。

Converting Errors to Optional Values エラーをオプショナルの値に変換する

You use try? to handle an error by converting it to an optional value. If an error is thrown while evaluating the try? expression, the value of the expression is nil. For example, in the following code x and y have the same value and behavior: あなたは、try?を使って、あるエラーをオプショナルの値に変換することによって取り扱うことができます。try?式を評価している間にエラーがスローされるならば、式の値はnilになります。例えば、以下のコードにおいてxyは、同じ値と挙動を持ちます。

  1. func someThrowingFunction() throws -> Int {
  2. // ...
  3. }
  4. let x = try? someThrowingFunction()
  5. let y: Int?
  6. do {
  7. y = try someThrowingFunction()
  8. } catch {
  9. y = nil
  10. }

If someThrowingFunction() throws an error, the value of x and y is nil. Otherwise, the value of x and y is the value that the function returned. Note that x and y are an optional of whatever type someThrowingFunction() returns. Here the function returns an integer, so x and y are optional integers. someThrowingFunction()がエラーをスローするならば、xyの値はnilです。そうでなければ、xyの値はこの関数が返す値です。xyは、たとえどんなものでもsomeThrowingFunction()が返す型のオプショナルです。ここに整数を返す関数があります、それでxyはオプショナル整数です。

Using try? lets you write concise error handling code when you want to handle all errors in the same way. For example, the following code uses several approaches to fetch data, or returns nil if all of the approaches fail. try?を使うことで、あなたに簡潔なエラー処理コードを書くことを可能にするのは、あなたがすべてのエラーを同じやり方で取り扱いたい時です。例えば、以下のコードはいくつかの取り組みを使ってデータを取ってきます、またはすべての取り組みが失敗するならばnilを返します。

  1. func fetchData() -> Data? {
  2. if let data = try? fetchDataFromDisk() { return data }
  3. if let data = try? fetchDataFromServer() { return data }
  4. return nil
  5. }

Disabling Error Propagation エラー伝達を抑制する

Sometimes you know a throwing function or method won’t, in fact, throw an error at runtime. On those occasions, you can write try! before the expression to disable error propagation and wrap the call in a runtime assertion that no error will be thrown. If an error actually is thrown, you’ll get a runtime error. 時にはあなたはあるスロー関数またはメソッドが、実際のところ、実行時にエラーをスローすることがないのを知っています。これらの場合には、あなたはtry!をその式の前に書くことによって、エラー伝達を抑制して、エラーはスローされないという実行時表明の中にその呼び出しを包み込みます。エラーが実際はスローされるならば、あなたは実行時エラーを受け取るでしょう。

For example, the following code uses a loadImage(atPath:) function, which loads the image resource at a given path or throws an error if the image can’t be loaded. In this case, because the image is shipped with the application, no error will be thrown at runtime, so it’s appropriate to disable error propagation. 例えば、以下のコードはloadImage(atPath:)関数を使います、それは画像リソースを与えられたパスでロードします、または画像がロードできないならばエラーをスローします。この場合、画像はアプリケーションとともに出荷されるので、エラーが実行時にスローされることはありません、それでふさわしいのはエラー伝達を抑制することです。

  1. let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")

Specifying Cleanup Actions クリーンアップ動作の指定

You use a defer statement to execute a set of statements just before code execution leaves the current block of code. This statement lets you do any necessary cleanup that should be performed regardless of how execution leaves the current block of code—whether it leaves because an error was thrown or because of a statement such as return or break. For example, you can use a defer statement to ensure that file descriptors are closed and manually allocated memory is freed. あなたはdefer文を使うことで、コード実行が現在のコードブロックから離れる直前に一揃いの文を実行するようにします。この文は、あなたに何らかの不可欠なクリーンアップを行わせます、それはどうやって実行が現在のコードブロックから離れるか ― それがエラーがスローされたためにまたはreturnまたはbreakのような文を理由に離れるかどうかに関係なく実行されるべきものです。例えば、あなたはdefer文を使ってファイル記述子が閉じられて手動割り当てメモリが解放されることを確実にします。

A defer statement defers execution until the current scope is exited. This statement consists of the defer keyword and the statements to be executed later. The deferred statements may not contain any code that would transfer control out of the statements, such as a break or a return statement, or by throwing an error. Deferred actions are executed in the reverse of the order that they’re written in your source code. That is, the code in the first defer statement executes last, the code in the second defer statement executes second to last, and so on. The last defer statement in source code order executes first. defer文は、現在のスコープが終了されるまで実行を延期します。この文は、deferキーワードと後で実行される文から成ります。延期される文は、制御をその文の外に、例えばbreakreturn文、またはエラーをスローすることによって移すいかなるコードも含んではいけません。延期された動作は、それらがあなたのソースコードに書かれた順序の逆に実行されます。すなわち、最初のdefer文のコードが最後に実行され、2番目のdefer文のコードが最後から2番目に実行され、等々。ソースコード順序での最後のdefer文は最初に実行されます。

  1. func processFile(filename: String) throws {
  2. if exists(filename) {
  3. let file = open(filename)
  4. defer {
  5. close(file)
  6. }
  7. while let line = try file.readline() {
  8. // Work with the file.(ファイル処理。)
  9. }
  10. // close(file) is called here, at the end of the scope.(close(file)がここで呼ばれます、このスコープの終わりで。)
  11. }
  12. }

The above example uses a defer statement to ensure that the open(_:) function has a corresponding call to close(_:). 上の例は、defer文を使って、open(_:)関数がそれと対応するclose(_:)への呼び出しを持つことを確実にします。

Note 注意

You can use a defer statement even when no error handling code is involved. あなたは、defer文を使うことが、エラー処理コードを伴わない時でさえも可能です。

Optional Chaining オプショナル連鎖

Concurrency 並行性