【Swift】Swift2.0からのエラーハンドリング:try, do-catchとdefer

Swift2.0からのエラーハンドリング の投稿一覧

概要

例外を投げる可能性のあるメソッドを呼び出す場合、引数にerror定義を書くだけで良かったものが外側に書く必要がでてきました。
この投稿でビルドに失敗したのも、Swift1.2から2.0に更新されたことを知らなかったことが原因です。

またSwiftでは、他言語でいうtry-catch-finally構文のようなものが用意されています。

構文

tryとdo-catch

例外を投げる可能性のあるメソッドを呼び出す時、メソッドの前にtryを記述する必要がある。
また、tryの行はdo{}で囲み、catchに例外時の処理を記述しなければならない。

enum Errors: ErrorType {
    case Error1;
    case Error2;
}

func throwError() throws {
    let a: Int? = nil;
    if (a == nil) {  /*aはnilなので、必ず例外を吐く*/
        throw Errors.Error1;
    }
}

do {
    try throwError();
} catch {
    print("catch");  /*例外をthrowError()が吐くので、この行が実行される*/
}
do-catchとdefer

doの中身が実行された後に必ず実行される処理をdefer{}内に記述できる。

enum Errors: ErrorType {
    case Error1;
    case Error2;
}

func throwError() throws {
    let a: Int? = nil;
    if (a == nil) {
        throw Errors.Error1;
    }
}

do {
    print("do1");
    defer {
        print("defer");
    }
    print("do2");
    try throwError();  /*この行で例外となるため、以降のdo{}内処理は全てスキップされる*/
    print("do3");
} catch {
    print("catch");
}

この場合、printされるのは次の順となる。
do1 > do2 > defer > catch

tryで例外となった場合、以降のdo{}内の処理は実行されない。
そのため、次の様な記述だとdefer{}内の処理は実行されない。

do {
    print("do1");
    try throwError();  /*この行で例外となるため、以降のdo{}内処理は全てスキップされる*/
    print("do2");
    defer {
        print("defer");
    }
} catch {
    print("catch");
}

この場合、printされるのは次の順となる。
do1 > catch

try!

プログラマが、例外を吐く可能性のあるメソッドが参照される時に必ず例外とならない確信がある場合は、tryに!を付けてdo-catchを省略して記述できる。

enum Errors: ErrorType {
    case Error1;
    case Error2;
}

func throwError() throws {
    let a: Int? = nil;
    if (a == nil) {
        throw Errors.Error1;
    }
}

try! throwError();  /*この行で例外となるため、ランタイムエラー*/
enum Errors: ErrorType {
    case Error1;
    case Error2;
}

func throwError() throws {
    let a: Int? = nil;
    if (a != nil) {
        throw Errors.Error1;
    }
}

try! throwError();  /*この行で例外とならないため、throwsの付くメソッドでもdo-catchを省略できる*/