HACKライフハックTRENDトレンドITエンジニアの求人・転職に+AgentGeekroidトップスキルスイスイSwift!第5回Swiftへの不安を解消しよう-実践編-skillスイスイSwift!第5回Swiftへの不安を解消しよう-実践編-2015.04.30Swiftスキル繁田卓二Tweet前回の導入編に続き、今回は実践編としてSwift移行への不安を払拭する。今回はObjective-Cでのアレはどう書けばよいのか。そもそも書けるのか、という不安を解消しよう。staticでグロバールな場所で変数を宣言し、定数的に扱うのが慣例であった。次のような宣言をよく目にしたことがあるだろう。@"定数文字列";これらはいずれもlet宣言子で記述すればよい。普通の変数宣言と同じであるが、クラス外に書けばグローバルな宣言となり、let宣言なのでプロセス生存中に値が変わることも無く、定数そのものの挙動を保証する。構造体はどう書く?Objective-CではC言語の要素である構造体が使用可能であったが、Swiftでは言語仕様そのものに取り込まれた。6以降で構造体にオブジェクトを持てなくなったが、Swiftでは改善されている。それどころか構造体自体にメソッドを実装できるなど一歩進化した拡張が見られる。iOSではおなじみの矩形座標を表す構造体CGRectの定義を見てみよう。Objective-Cはこうだ。size;};構造体の中にCGPointとCGSizeという構造体が入っているが基本的には値を保持した集合体にすぎない。次にSwiftの定義を見てみよう。CGSize}定義自体はほぼ変わらない。次のような行が定義されている。extension宣言は後述するが、Objective-Cのカテゴリに相当する。これを見るとCGRectにコンストラクタやメソッドを後付で宣言しているのがわかるだろう。Bool}ここまで来るとクラスとの違いは?という疑問が湧くが、一番大きな違いとしては値代入時に参照渡しではなく値渡しとなる点が異なる。Blocks構文はどう書く?Objective-Cの機能の中では比較的歴史の浅いBlocks構文はその強力な機能の反面、記述の難解さにおいて多くのプログラマを苦しめてきた。Swiftではどのように改善されているのか見てみよう。引数、返り値なしのBlocks定義。引数、返り値ありのBlocks定義。引数、返り値なしのBlocks定義。引数、返り値ありのBlocks定義。in~処理~}Swiftではクロージャーとして生まれ変わった。いう形式でモダンな言語に近い構文となっている。それでも一部の開発者にはウケが悪いのかfuckingswiftblocksyntax.comというドメインのサイトがある。Blocks登場時に現れたfuckingblocksyntax.comと同じくチートシートのみのサイトなので、記法を忘れた際はここを訪れると良いだろう。プロトコルはどう書く?プロトコルはJavaのInterface宣言のように実装の無いクラス宣言だ。Objective-Cとの違いは、宣言したメソッドやプロパティは全て必須となる点だ。従来のように@requiredや@optional宣言子で実装の可否を選択させることはできない。~メソッドの実装~}}プロトコルで宣言したメソッド、プロパティの全てが必須となるため、Objective-Cからの移行の場合は設計を見直す必要も出てくるだろう。その場合は、プロトコル宣言時に@objc属性をつけoptional修飾子を付けると良い。カテゴリはどう書く?Objective-Cには定義済みのクラスを拡張する仕組みとしてカテゴリという機能があった。SwiftではExtensionという仕組みがこれにあたる。Objective-Cとの違いはメソッドだけでなくプロパティもクラスに後付けできるという点が違う。定義済みの列挙型や構造体にもExtensionでメソッドやプロパティが拡張ができる。下記はFoundationにて定義されているNSURLクラスに、ローカルホストかどうかを返すメソッドを追加した例だ。オートリリースプールSwiftではメモリ管理は不要、というのは間違いで、Objective-C同様に参照カウンタ方式のメモリ管理がおこなわれている。コンパイラが文脈を判断し、自動でメモリの解放コードを挿入し中間コードを生成。不要になったオブジェクトはオートリリースプールに溜め込まれ、イベントループが処理されるたびに開放されてる。この辺りの仕組みはARCが導入された辺りから開発者が意識しなくて良くなったが、それでも同じイベントループ内で大量のメモリを使用する場合は、開発者が適宜オートリリースプールを用意する必要がある。Objective-Cでは@autoreleasepoolという修飾子により文脈を記述できたが、Swiftでも同様の記述で実装できる。{//~メモリを多く使用する処理~}}注意すべき点として、Objective-Cでの@autoreleasepool修飾子以降の括弧内はBlocks構文ではなく、反対にSwiftのautoreleasepool構文内の文脈はクロージャーとして実行される事だ。Objective-Cのように文脈上で処理されるコードではないため、returnやbreakはクロージャーの外には影響せず内側で処理される。上記のSwiftのコードの場合において、autorelasepoolクロージャー内でreturnやbreakを記述してもfor文のループが終了するわけではない点に注意しよう。例外処理は?Objective-Cでのアプリ開発では習慣としてtry~catchでの例外処理はあまり記述されることは無かった。構文としては用意されているが、特にARC環境においてはランタイム時の例外で文脈がスキップされることにより参照カウンタに齟齬(いわゆるメモリリーク)が起きやすい、という理由から推奨はしていなかった。Swiftでは何とtry~catch構文がサポートされていない。pointer的な例外は起こりにくくなっているとは言え何とも思い切りの良い決断だ。従来の例外クラスNSException自体はSwiftからも使用可能なため、どうしても例外をハンドルする必要があるのであれば、間にObjective-Cクラスを用意し、擬似的に例外をキャッチする仕組みを用意すると良いだろう。まとめSwiftには多くの文法や作法があるが、Objective-Cからの移植に関して言えば実はそれほど多くのことを学ぶ必要は無い。手元にObjective-Cのプロジェクトがあれば、それを徐々にSwift化していく事は最初の実践課題としては申し分ないだろう。完成した頃にはもうObjective-Cには戻れないはずだ。ビールをこよなく愛するゆるキャラ系プログラマ。Webアプリ開発からMacアプリ開発を経て現在はiOSアプリ開発に没頭。弱点はAndroid。Corporation。