try?のうまい使い方

Sunday, February 21, 2016

Swift2.0からエラーハンドリングが追加され、tryを使えるようになりました。
また、Xcode7 beta6(あたり?)から、trytry!に加えtry?が追加されました。
これにより、柔軟にtryを使えるようになります。

まず、通常のtryですが、

do {
    let object = try doSomething()
} catch (let error) {
    print(error)
}

のように使います。必ずdo{ } catch {}で用いて、tryはdo文内に書く必要があります。
次にtry!ですが、上記のdo{ } catch {}を使わず、 例外がキャッチされない のを条件にして書くことができます。

    let object = try! doSomething()

ただ、もしdoSomething()が例外を発生させた場合は強制終了します。
必ず例外が起こらない状況で、do{ } catch {}でネストさせたくない場合はこれを用います。

そして、try?の出番です。
これは、 例外が発生しなければその関数の戻り値を返し例外が発生すればnil を返すといったものになります。
勘違いしやすいのですが、try?を指定して例外が発生した場合はエラーが変数に入るのではなく、 nil が返ってきます

func doSomething() throws -> String {
    return "done!"
}

let object = try? doSomething()
// objectはString?型

こちらもtry!と同様、do{ } catch {}を使わずに済むので、 do{ } catch {}を使う必要がなく、例外のエラーが何であるか必要なく、処理が成功するかしないかが必要な場合は、
このtry?を使うとより簡潔に書けます。

  • 例1: 値のチェック
func doSomething() throws -> String {
    return "done!"
}

if let str = try? doSomething() {
    print(str)
}

guard let str = try? doSomething() else {
    return
}
print(str)

if let文もしくはguard let文で例外が起きなかった場合の値をキャッチできます。

  • 例2: 例外が起こりうるかもしれないが、エラーを必要としない場合
_ = try? NSFileManager.defaultManager().removeItemAtPath("path")

このように、removeItemAtPathの結果が成功であっても、例外発生であっても、特に例外の処理をしない場合は、do{ } catch {}を書くよりは
簡潔に済ませられます。 ただ、removeItemAtPathのように、関数の返り値がVoidであっても、try?を使う場合は、Voidまたはnilが返るようになるので、
_ =のようにして、使わない値を捨てる必要があります。

このtryが出現する前から、Either型Resultと称されるものが出てきていて、エラーハンドリングをそれに委ねられることが多く、
スルーされがちなtryさんですが、使いこなせると表現の幅が広がるので、是非tryを、できればtry?さんも使ってあげてください。

techSwiftTips

protocolを使って冗長的な関数のオーバーロードを減らす

キーボードの「次へ」を押して、次のTextField,TextViewに移動する処理を簡単にしたFormChangeableを作ってみた