Swift 2では新しいエラーハンドリング機構が追加されました。他言語でいうところの例外処理のようなものです。
エラーを投げる (throw)
まず、下記のようにしてエラーを定義します。エラーはErrorType
を継承している必要があります。
enum MyError: ErrorType {
case UnexpectedError
}
実際にエラーが発生する場所では、下記のようにthrow
を使ってさきほど定義したエラーを投げます。
func myfunc() throws {
throw MyError.UnexpectedError
}
このとき、myfunc()
にthrows
と修飾されている点に注意してください。throw
を使ってエラーを投げる場合、これがないとコンパイルエラーとなります。また、ErrorType
を継承していないものを投げようとする場合にもコンパイルエラーになります。
エラーを受け取る (do/try/catch)
throws
で修飾された関数を呼び出す場合、呼び出し側でエラーハンドリング処理を準備しなければなりません。
エラーハンドリングを行うには、下記のようにdo
句のなかでエラーが発生しうる関数にtry
をつけて呼び出します。
do {
try myfunc()
}
catch MyError.UnexpectedError {
print("caught")
}
throws
で修飾されている関数を呼び出す場合、このtry
がないとコンパイルエラーになります。逆に、throws
で修飾されていない関数にtry
をつけて呼び出しても、警告は出ますがコンパイルエラーにはなりません。
エラーが発生すると、対応するcatch
句が実行されます。発生しうるエラーに対して対応するcatch
句が揃っていない場合、コンパイルエラーになります(が、現時点のBetaではmain()
内に書いた場合はコンパイルエラーにならないようです)。
try
つき呼び出しをdo
句の外で行ってもコンパイルエラーになりますが、これも現時点のBetaではmain()
内に書いた場合にはコンパイルエラーにならないようです。
引数つきエラー
下記のように、エラーには引数をつけることができます。エラーの引数はcatch
句で受け取ることができます。
enum MyError: ErrorType {
case UnexpectedError
case CountError(count: Int)
}
func thrower(c: Int) throws {
if c > 0 {
throw MyError.CountError(count: 2)
}
else {
throw MyError.UnexpectedError
}
}
do {
try thrower(10)
} catch MyError.UnexpectedError {
print("unexpected")
} catch MyError.CountError(let count) {
print(count)
}
main()
内ではこのようなドキュメント通りの記述ができますが、現時点のBetaでは関数内に記述する場合に、このような複数のエラータイプがあるケースですべてのタイプを網羅するcatch
句を書いてもコンパイルエラーになるケースがあるようです(コメント欄参照)。
エラーを無視する
throws
で修飾されている関数を呼び出す際、絶対にエラーが発生しないことがわかっている場合には、下記のようにtry!
をつけることでエラーハンドリング処理を実装せずに呼び出すことができます。
try! myfunc()
このような呼び出し方をした場合にエラーが発生すると、アプリケーションはクラッシュします。
おわりに
Swift 2で新しく追加されるエラーハンドリング処理について記述しましたが、現時点(Xcode 7.0 Beta 7A120f)ではコンパイラの挙動が不安定で、通るはずのないコードがコンパイルを通ってしまったり、またその逆もあったりします。Swift自体がよく仕様が変わる言語なので、常に最新のドキュメントを参照するようにしましょう。