Swift 2 の新しいエラー処理を理解しようと試みます。私がやったことは次のとおりです。まず、エラー列挙型を宣言しました。
enum SandwichError: Error {
case NotMe
case DoItYourself
}
そして、エラーをスローするメソッドを宣言しました (例外ではありません。エラーです)。そのメソッドは次のとおりです。
func makeMeSandwich(names: [String: String]) throws -> String {
guard let sandwich = names["sandwich"] else {
throw SandwichError.NotMe
}
return sandwich
}
問題は呼び出し側にあります。このメソッドを呼び出すコードは次のとおりです。
let kitchen = ["sandwich": "ready", "breakfast": "not ready"]
do {
let sandwich = try makeMeSandwich(kitchen)
print("i eat it \(sandwich)")
} catch SandwichError.NotMe {
print("Not me error")
} catch SandwichError.DoItYourself {
print("do it error")
}
行の後にdo
コンパイラは と言いますErrors thrown from here are not handled because the enclosing catch is not exhaustive
。しかし、私の意見では、enum には 2 つのケースしかないため、これは網羅的ですSandwichError
。
通常の switch ステートメントの場合、Swift はすべてのケースが処理されるとそれが網羅的であることを理解できます。
ベストアンサー1
Swift 2 のエラー処理モデルには、網羅性と回復力という 2 つの重要なポイントがあります。これらを組み合わせると、do
/catch
ステートメントで、スローできるエラーだけでなく、起こり得るすべてのエラーをキャッチする必要があるということになります。
関数がスローできるエラーの種類を宣言するのではなく、エラーをスローするかどうかだけを宣言することに注意してください。これは、ゼロ・1・無限のような問題です。他の人 (将来の自分を含む) が使用できるように関数を定義する人として、関数のすべてのクライアントが、スローできるエラーなど、関数の実装におけるすべての変更に適応するようにする必要はありません。関数を呼び出すコードは、そのような変更に対して耐性があることが必要です。
関数はどのようなエラーをスローするか (または将来スローする可能性があるか) を判断できないため、catch
エラーをキャッチするブロックは、関数がスローする可能性があるエラーの種類を知りません。したがって、わかっているエラーの種類を処理するだけでなく、わからないエラーの種類もユニバーサル ステートメントで処理する必要があります。catch
そうすれば、関数が将来スローするエラーのセットを変更しても、呼び出し元は引き続きエラーをキャッチできます。
do {
let sandwich = try makeMeSandwich(kitchen)
print("i eat it \(sandwich)")
} catch SandwichError.NotMe {
print("Not me error")
} catch SandwichError.DoItYourself {
print("do it error")
} catch let error {
print(error.localizedDescription)
}
しかし、ここで止まってはいけません。この回復力の考え方についてもう少し考えてみましょう。サンドイッチを設計した方法では、エラーを使用するすべての場所でエラーを記述する必要があります。つまり、エラー ケースのセットを変更するたびに、エラーを使用するすべての場所を変更する必要があります... あまり楽しいことではありません。
独自のエラータイプを定義する目的は、そのようなものを一元管理できるようにすることです。description
エラーの解決方法:
extension SandwichError: CustomStringConvertible {
var description: String {
switch self {
case NotMe: return "Not me error"
case DoItYourself: return "Try sudo"
}
}
}
そして、エラー処理コードでは、エラー タイプにそれ自体の説明を要求できます。これで、エラーを処理するすべての場所で同じコードを使用でき、将来起こりうるエラー ケースも処理できるようになります。
do {
let sandwich = try makeMeSandwich(kitchen)
print("i eat it \(sandwich)")
} catch let error as SandwichError {
print(error.description)
} catch {
print("i dunno")
}
これにより、エラー タイプ (またはそれらの拡張機能) がエラーを報告する他の方法をサポートする道も開かれます。たとえば、UIAlertController
iOS ユーザーにエラーを報告するための の表示方法を認識するエラー タイプの拡張機能を持つことができます。