しめ鯖日記

swift, iPhoneアプリ開発, ruby on rails等のTipsや入門記事書いてます

Swift2.0で追加された try, do-catch, defer を試してみる

do-catch構文の基本的な使い方は下の通りです。
ErrorTypeを使った独自エラーを作り、独自エラーのthrowとcatchをする事ができます。

enum MyError: ErrorType {
    case Error1
    case Error2
}

do {
    let a: Int? = nil
    if (a == nil) { throw MyError.Error1 }
} catch MyError.Error1 {
    print(1)
} catch {
    print(2)
}

catchに来たエラーは下のように取得できます。

enum MyError: ErrorType {
    case Error1
    case Error2
}

do {
    let a: Int? = nil
    if (a == nil) { throw MyError.Error1 }
} catch let error {
    print("\(error)")
}

メソッド中でcatchしたくない場合はメソッド定義にthrowsを付ければ良さそうです。
Javaのようにthrowsにエラータイプを指定する方法は見つかりませんでした。

func method() throws -> String {
    let a: Int? = nil
    if (a == nil) { throw MyError.Error1 }
    return "String"
}

throws付きのメソッドを呼び出す際はtrydo-catchが必要です。

do {
    let str = try method()
} catch {
    print(2)
}

try!を使えばdo-catchは不要です。
しかしmethod内で例外が投げられた時はアプリが落ちます。

let str = try! method()

do-catchせずに呼び出し元へエラーを伝えたい場合はメソッドthrowsを付けます。

func method() throws {
    let a: Int? = nil
    if (a == nil) { throw MyError.Error1 }
}
    
func method2() throws {
    try method()
}

do {
    try method2()
} catch {
    print(1)
}

他言語のfinallydeferを使って実現します。
deferで定義された処理はブロックの最後に必ず処理されます。
下のようにdeferに処理を登録すればmethod中で例外が発生した場合もdeferの中身が呼ばれてくれます。
defertry method()の後ろで行っても効果は発揮しないので、そこだけ注意する必要があります。

// 1 → 2 → 3 という順番で出力される
do {
    defer {
        print("2")
    }
    print("1")
    try method()
} catch {
    print("3")
}