defer処理
必ず処理するdefer処理
関数処理にかかる時間を計測しようとした場合に、関数呼び出しの前後で現在時刻を出力する処理を記述することを考えることがあると思います。次のような例です。現在日付をプロパティとして持つDateクラスのインスタンスをprint文で出力することで、その時点での時刻を出力しています。
1 2 3 4 5 6 7 8 9 10 11 12 |
//エラーをthrowする可能性がある関数 func longMethod()throws{ <省略>時間がかかる処理 } //エラーハンドリングが必要なlongMethod関数を利用 do { print("処理開始時間: \(Date())") try longMethod() // try句を付ける必要がある print("処理終了時間: (Date())") } catch { print("エラー発生") } |
実行結果例は次のとおりです。処理開始時間と処理終了時間の差が20秒であることがわかります。
1 2 |
処理開始時間: 2018-11-01 02:10:10 +0000 処理終了時間: 2018-11-01 02:10:30 +0000 |
一見問題なさそうですが、例で使用しているlongMethod関数は、エラー時にthrowを発生させる可能性があります。longMethod関数内でthrowが発生した場合には、longMethodの処理が中断され、catch処理が行われます。次の例は、throwが発生した場合の出力結果です。
1 2 |
処理開始時間:2018-11-01 02:10:10 +0000 エラー発生 |
処理終了時間が出力されていないことがわかります。エラー発生時にも処理終了時間を出力したい場合にはどうしたらよいのでしょうか?
その際に活躍するのがdeferです。defer内に定義した処理は、スコープ終了時に呼び出されることが保証されます。deferは次の書式で宣言できます。
1 2 3 |
defer{ 「スコープ終了時に行いたい処理」 } |
deferを使用して、先ほどの処理終了時間がエラー時にも出力されるようにするには、次のように記述します。
1 2 3 4 5 6 7 8 9 10 11 |
//エラーハンドリングが必要なdoubleUp関数を利用 do { // 処理終了時に必ず行う処理 defer{ print("処理終了時間: \(Date())") } print("処理開始時間: \(Date())") try longMethod() // try句を付ける必要がある } catch{ print("エラー発生") } |
deferを利用しているコードでthrowが発生しなかった場合と、throwが発生したときの実行結果は、それぞれ次のようになります。
1 2 |
処理開始時間: 2018-11-01 02:10:10 +0000 処理終了時間: 2018-11-01 02:10:30 +0000 |
1 2 3 |
処理開始時間:2018-11-01 02:10:10 +0000 処理終了時間:2018-11-01 02:10:15 +0000 エラー発生 |