前々回, 前回で外部のJSONファイルをデータとし, SwiftUIは表示の役割に集中するコードを作ることができました. しかし3-2-1で作成したJSONの読み込みコードは少し作りかたに不安があります.
今回は3-2-1のコードをより良いものにするのが目的です.具体的には以下のことです.
- 例外処理をきちんと処理する
- 例外が発生した時にエラーをコンソールに出す
- Optional(!や?)をきちんと処理する
まずは読み込みの関数の改善です.
- Resource.swiftの load( name: ext: ) の例外処理を行う
- 処理を do { ~~ } で包む (doの中で発生した例外を拾うようになる)
- try!は例外を潰してしまう ので, !を外した try に置き換える
- tryで例外が起きた時の処理を catch { ~~ } に書く
- catch内ではエラーをコンソールに出すprintを書く
- データ取得に失敗したので, 空のData()をreturnする
コード1
|
|
Appの見た目は変わりませんが, do ~ catchを導入したことでJSONファイルの中身が間違っていたときなど, Appは落ちなくなります. またコンソールにファイルが読み込めなかったと表示されるようになるため, JSONファイルがおかしいのかな?とわかりやすくなります.
このコードをさらに磨いてみましょう. Bundle,main.urlの ! に対応します.
- Bundle.main.urlは最後に!をつけている(強制アンラップ)
- ファイル名にミスがあると, Bundle.main.urlは nil (無) を返す
- このように値の存在が保証されない変数を Optional変数 という(!や?のついた型)
- URL
- URL型. 中にURLが入っていることが保証される
- URL?, URL!
- Optional
型. URLが入っていたり,いなかったりする(nil)
- Optional
- URL
- 中身がnilのOptional型を強制アンラップ(!をつける)しようとするとAppが落ちる
- URLをミスしてもAppを落とさず,URLが間違っていることを伝えるようにしたい
- guard let url = … else { ~(nilだった時の処理)~ } を書く
コード3
|
|
guard let ~ else 構文はurlに値を入れようと試みます. 成功すればurlに値を入れて先に進みます.urlは値があるのが保証されますのでOptionalを外してくれます.
しかしBundle.main.urlが失敗した場合はnilになってしまいます.強制アンラップではAppが落ちますが,guardはurlへの代入の失敗を検知した時, elseブロックに処理を移動させます. guardのelseブロックの中ではurlが作れなかったことを伝える処理を書きます. 今回の場合URLの指定ミスになるので「ファイルがありません」とコンソールに表示するようにします.
以上2つの改善を加えることで, JSONファイルがない場合は「ファイルがありません」と出ますし, ファイルはあるがJSONの中身が間違っている場合などは「ファイルが読み込めませんでした」と別のエラーを指摘してくれるようになります.
続いてPhotoDataの改善も行います.
- PhotoData.swiftを開き, static func parse( json: ) を例外に対応させる
- 基本的に上記と同様に do { ~~~ } catch { ~~~ } の処理を書く
- do{ ~ }で包む, try! は tryに置き換える
- 例外発生時の処理をcatchに書く
- error.locaizedDescription をprintする. 例外の内容がコンソール表示される
- エラーの時は空の配列 をreturnする
- 基本的に上記と同様に do { ~~~ } catch { ~~~ } の処理を書く
コード2
|
|
PhotoData.parseの例外に対応すると何が良くなるかというと, Resource.loadではJSONファイルの読み込み自体はうまくいったけれど, JSONの形式が異なっていてPhotoDataに必要なデータがなくて変換できなかったことが伝えられるようになります.
このような例外やOptionalの処理を丁寧に書くのは手間はかかりますが, ミスがあった時にわかりやすいメッセージを出すことなどができるのでメリットは大きいです.