スイスイSwift!第6回iOS9で進化するSwift2.0の実力
skill

スイスイSwift!第6回
iOS9で進化するSwift2.0の実力

2015.09.24

ent121_img01.jpg

iOS SDK 9と共に正式リリースされたXcode7。このメジャーバージョンナンバーのアップグレードは単に毎年刷新される iOS SDK のバージョンアップだけではなく、Swiftのメジャーバージョンアップを含んでもいる。そう、Swift2.0の登場である。今回は大きく進化した Swift 2.0 の機能についておさらいしてみよう。
繁田 卓二

■ 概要

昨年6月のWWDCで発表されたSwiftも、今年のWWDCには早くも2.0のナンバリングを与えられた。iOS SDK のように毎年メジャーバージョンがアップするのか、それともWeb2.0的な革新的バージョンアップを示すのかは定かではないが(※1)、少なくとも言語仕様を大きく変える大幅な仕様変更が盛り込まれている。

ent121_img02.jpg

出展: YouTube Apple WWDC2015 (https://www.youtube.com/watch?v=_p8AsQhaVKI)

※1) Objective-CでもMac OS X 10.5のリリース時に Objective-C 2.0 と呼ばれるバージョンがリリースされた。ちょうど Web 2.0 など「2.0」という言葉が革新的進化という意味で盛んに使われていた時期だ。

Swift2.0で大きく追加・変更された言語仕様は下記の通りだ。

  • - 新しいエラーハンドリングモデルの追加。
  • - 新しい制御構文 guard / defer の追加。
  • - プロトコルに実装が拡張可能。
  • - if文でのパターンマッチングの追加。

また、WWDCではオープンソース化や、Linuxへの対応についても発表された。言語仕様だけでなくAppleの方針面で大きな変化が見られる。これまでクローズドな進化を遂げ、他のプラットフォームでの展開は一切認めなかったAppleが180度転回したのである。まさに 2.0 にふさわしい大型アップデートと呼べるだろう。

ent121_img03.jpg

今回はこれらのうち言語仕様について大きく変化のあったエラーハンドリングモデルと新しい制御構文 guard / defer にフォーカスを当て解説しよう。

■ 新しいエラーハンドリングモデル

一般的な言語では try{} ~catch {} 構文により例外エラーを処理するための構文が予め用意されている。Objective-Cでも古くから実装されていたが、Swiftでは例外処理はサポートされていなかった。このためObjective-Cで書いた汎用的な例外ブロックをSwiftから使用して擬似的に例外処理をおこなうなどの方法を使用する開発者も多かった。

Swift2.0では正式にtry~catch構文が採用され、より安全なエラーハンドリングを行うことが可能となった。Objective-Cでは自律回復できる例外が少なく例外が発生した時点で負けというそれはそれで潔さはあったが、やはり他の言語の開発者にとっては例外処理が書けないのは欠点にしか思えないだろう。

まずは例外を投げる側の実装を見てみよう。他の言語同様にthrow文によって、例外の内容を投げることになる。下記は findcatNameByID() と命名した関数で IDを渡して猫の名前を取得する関数を用意した。引数のidが、予め定義された猫の数よりも大き(or小さ)ければ例外をthrowし、また、IDの範囲によって、「~くん」「~ちゃん」を付けて返すように設計した。throwする例外は ErrorType プロトコルを適合した列挙型を throw するところにも注目しておこう。

ent121_img04.jpg

この例外をキャッチするためには、Swift2.0では try{} ~catch {} ではなく、do { ~ } catch {} という構文を使用する。また、例外の発生が予測される処理文の先頭に try を付ける必要がある。Doブロック内のtry句を付けた直後の処理のみ例外キャッチの対象となる。例外の予測箇所が複数ありキャッチの必要があれば全てにtry句を付ける必要がある。これはなかなか独特の文法ではあるが、なんでもかんでもキャッチの対象とするよりは例外元が明確となって良いだろう。
例外発生時はその後の構文はスキップされcatchブロックに遷移する。下記コードはそのままでは例外は発生しないが、引数をマイナス値や6以上の値とすることによって、該当する列挙型の catch ブロックに処理がスキップされるのが確認できるだろう。
(ただしロジック上はFindCatErrors.InvalidCatID以外の例外が投げられることはありえない。)

ent121_img05.jpg

また、Java や Objective-C にもあった finally ステートメントは Swift 2.0 では採用されなかった。これは後述の defer 構文を使用することにより、より柔軟な終了処理が可能だからである。これについては後ほど解説しよう。

■ 新しい制御構文の追加

Swift2.0では新たに guard / defer というステートメントが追加された。いずれもスマートなコードの記述に不可欠なものなので積極的に使いたい。

● guard 構文
guard は条件を満たしていない場合に処理すべきコードを記述する。Early Exit と呼ばれ、メソッドの引数をチェックし条件に満たしていない場合にスコープから抜けるような場合に使用する。期待値ではない場合に処理を抜けるということは、その先のプログラムにおいてチェックした値が安全であるということが明白となる。可読性もアップするということだ。

前述の findCatNameByID() 関数の引数チェック部分をguard構文で書きなおすと下記のようになるだろう。

ent121_img06.jpg

一見 if 文と似ているが、if 文では書き手次第でチェックした値が安全であった場合の処理を if ブロックの中に書くか else に書くかが変わることがある。また場合によっては if 文のネストが多階層になり可読性を失いがちだ。if 文でも Early Exit として return や throw すれば良いが、上記の構文のように let で宣言した値が guard ブロック以降のスコープでも使用できる点が違う。より安全に値を扱うことができるという点でも差が出てくるだろう。

● defer 構文
defer で宣言したブロック内のコードは、宣言したスコープを抜ける際に必ず実行されることになる。
スコープとは通常は関数やメソッドの中であれば波括弧”{?}”の範囲であるが、return やbreakなどのステートメントを使用した場合などは以降の処理をスキップする。前述の例外発生時も同様だ。こういった時に忘れずに終了処理をおこないたい場合に使用する。

例えばよくあるのが、時間のかかる処理を実行する直前に画面上のローディングインジケーターのアニメーションを開始し、正常に処理が終了したタイミングでアニメーションを終了する場合がわかりやすいだろう。途中で例外が発生した場合などは以降のコードは実行されないため、アニメーションの終了処理を忘れがちで、いつまでもインジケーターがぐるぐる回った状態になってしまう。例外を投げる直前でアニメーション解除を行えば良いが、複数の箇所から例外を投げる必要がある場合などは解除処理を複数記述する必要があり、コードの見通しは悪くなる。こういった場合に defer 文でアニメーションを解除するコードを宣言しておけば、途中で例外が発生したり return で処理が終了したとしても必ずアニメーション解除が呼ばれることになる。 もちろん正常終了した時も呼ばれる。また、deferは複数宣言や、ネストして宣言することも可能だ。先ほどswiftの例外処理にはfinally構文が無いと説明したが、deferを使用すればそれ以上に柔軟な終了処理を記述できるようになるだろう。

ent121_img07.jpg

■ まとめ

2.0の登場でさらに便利になったSwift。その魅力に惹かれ、さらに開発者が増えるのではないかと予測される。それに加え、オープンソース化したことにより、より多くのフィードバックが得られることになるだろう。

まさに内堀も外堀も固めたSwift 2.0。今後はさらに驚異的なスピードで進化を遂げることになるだろう。 今後の動向がますます注目される言語である。

原稿:繁田卓二
qnote最高技術責任者。猫とビールをこよなく愛するゆるキャラ系プログラマ。
Webアプリ開発からMacアプリ開発を経て現在はiOSアプリ開発に没頭。弱点はAndroid。

この記事はどうでしたか?

おすすめの記事

キャリアを考える

BACK TO TOP ∧

FOLLOW