ログアウト

04 Swiftコードの書き方: エラー関連処理

エラー関連処理

処理の途中でエラーが発生した際に、そのエラーを通知し(エラー発生情報をオブジェクト間で渡す)、エラーごとに適した処理をプログラマが行えるようにするための仕組みがSwiftには用意されています。関数・呼び出しの書き方に追加していく記法なので、関数の書き方を思い出しながら進めていきましょう。

エラー発生時の処理の流れ

バケツリレーのように、A→B→Cと関数が呼び出されています。
この図では、最初に呼び出してきた関数Aと、エラーが発生した関数Cに注目してください。
エラーが起こりうる関数(ここではC)に、「今ここでエラーが発生しました!」という情報を投げるためのthrow処理を記載し、その処理は最初の関数(ここではA)に通知されます。このAに、エラー発生時の処理(エラーが起こったら何をするかというコード)を記述しています。間のBにエラー情報は通知されません。

1、エラー通知:エラーが起こりうる関数側で記載するthrow処理
2、エラー対応の処理:戻り値を受け取る側(関数呼び出し側)で記載するdo-catch文

この2つに分けて書き方を見ていきましょう。

throw処理

関数Cのような、エラーの起こりうる可能性がある関数は、次のように記述します。

関数名()の後にthrowsと記載することで、「この関数でエラーが起こる可能性がある」ということを明示します。
エラーが起きた時に、throwとすることで、「エラーが発生した」という情報を呼び出し元に渡します。

throwを使って渡すのは、「エラーが発生したという情報」です。
これは、Errorプロトコル(Apple提供)を適用したenumを作成し、それをthrowの後に呼び出して、呼び出し元に渡します。
Errorプロトコルとは、適用した型はエラーを表現する型として扱う、ということを示すための特別なプロトコルで、実装するプロパティやメソッドはありません。

doubleUp関数は渡された引数を2倍にして返します。
この渡された引数valueの値が「0」よりも小さいときに「invalidValue(意:無効な値)」というエラーデータが渡される(throw)記述になっています。

それではこのdoubleUp関数の呼び出し側の処理を見てみましょう。

 

do-catch文 try文

 関数Aのような、エラーが起こりうる関数を呼び出す側は、次のように記述します。
(「//エラーハンドリングが必要な〜」というコメント以下からです。)
(ここでは冒頭の図の関数A・関数Bを省略して、関数C(下記のdoubleUp関数)を、関数の中からではなく直接呼び出しています。Playgroundでそのまま試してみてください。)

throwsが宣言されている関数を利用する場合は、throwで通知されるエラーをハンドリングする必要があります。
※ハンドリング:状況に合わせて対応処理すること

要は返ってきた情報に合わせてそれぞれに対応する処理を記載します。

do { } で囲まれた処理は、通常の値が戻ってきた時の処理、
catch  { } で囲まれた処理は、指定したエラー情報が渡された時に行う処理です。
catch文はエラーごと(enum にエラーパターンを複数作る)に複数書けます。(do-catch-catch...と続けて書く事ができる)

サンプルコードで正常処理とエラー処理を実行して動作を確認しましょう。

 

必ず処理するdefer処理

 throws, do-catchの内容を踏まえた上で見ていきましょう。
関数の処理にかかる時間を計測しようとした場合に、関数呼び出しの前後で現在時刻を出力する処理を記述することを考えることがあると思います。次のような例です。現在日時をプロパティとして持つDateクラス(Xcodeで提供されているクラス、import UIKitの記載が必要)のインスタンスをprint文で出力することで、その時点での時刻を出力しています。

 結果例は次のとおりです。この時、処理開始時間と処理終了時間の差が20秒であることがわかります。

 一見問題なさそうですが、例で使用しているlongMethod関数は、エラー時にthrowを発生させ、catch処理が行われる可能性があります。次の例は、throwが発生した場合の出力結果です。

 処理終了時間が出力されていないことがわかります。エラー発生時にも処理終了時間を出力したい場合にはどうしたらよいのでしょうか?

 その際に活躍するのがdeferです。defer内に定義した処理は、スコープ(=範囲:deferが書かれた場所の{ }内のこと)終了時に呼び出されることが保証されます。deferは次の書式で宣言できます。

 deferを使用して、先ほどの処理終了時間がエラー時にも出力されるようにするには、次のように記述します。

 deferを利用しているコードでthrowが発生しなかった場合と、throwが発生したときの実行結果は、それぞれ次のようになります。

 

 →次ページ「00 概要(レクチャー3:iOSの部品)」へ