開発生産性や品質を向上させたいiOSアプリ開発者のためにObjective-CからSwiftへ移行するメリットや手順、注意点など勘所をまとめて紹介します。
iOSアプリ開発者の皆さま、もう「Swift」でアプリを開発していますか? 登場した日から一年以上たち、今はバージョン2.0のベータ版まで出ているプログラミング言語Swift。初期はコンパイルの遅さや不具合の多さが目立ったのですが、最近はその辺りの問題が解消されて非常に使いやすくなってきています。
そろそろ、ぜひ移行をお勧めしたいのですが、既存のObjective-Cアプリを移行するのはなかなか大変な面もあると思います。チームで開発している場合は自分以外の開発者や関係者へ周知するコストも掛かりますし、Swiftへ移行する際のトラブルを思うと、いろいろな不安がつきまとうでしょう。
本稿では、そういった不安が少しでも解消されるように、アプリ開発のプログラミング言語をObjective-CからSwiftへ移行するメリットや手順、注意点など勘所をまとめて紹介します。
なお本稿は、SwiftやObjective-Cの書き方や言語仕様についてある程度分かっている方を対象読者としていますので、SwiftやObjective-Cの書き方や言語仕様について知りたい方は、下記連載などを参照してください。
まずは、iOSアプリをSwiftで開発することによるメリットを紹介します。Swiftの長所はいろいろとありますが、大きく分けると下記の二つかと思います。
以下でそれぞれについて説明していきます。
Swiftは、「型が違うクラスへの代入禁止」「nilの扱いにおけるObjective-Cからの変化」によって厳密な言語仕様を持っています。
特に「nilの扱いにおけるObjective-Cからの変化」はアプリ開発での不具合を大きく減らしてくれます。なぜならSwiftは、Objective-Cと違って、通常の変数がnilを持つことがないからです。Swiftの変数にnilを持たせたい場合は「Int?」などのように「?」を付けて「Optional(オプショナル)型」として定義する必要があります。これによって、変数に予想外の値が入る現象を減らせます。
アプリを開発していると、nilが入らない想定の変数にnilが紛れ込むことで正しく動かない現象が起こります。特に、インスタンス変数のようにいろいろな箇所から参照される値はnilが紛れ込みやすいですし、どこで紛れ込んだかの特定が難しいです。
しかしSwiftでは、オプショナル型以外にnilを入れた場合にはコンパイルできないので、そういった不具合も起きにくくなります。
let value: MyValue = nil // → コンパイルエラーになる let value: MyValue? = nil // → エラーにならない
他にも、「型が違う変数へキャストした場合に即時クラッシュする」「配列やディクショナリに型指定ができる」などの言語仕様により、Objective-Cよりも不具合に気が付きやすくなっています。
SwiftはObjective-Cから構文が大きく変わり、シンプルでモダンな書き方ができるようになりました。特に型推論は強力な機能で、多くの場合で型の省略が可能です。
let value1 = 1 let value2 = method() let value3 = value1
var value: Int func method(arg1: Int) -> String { // ... }
SwiftとObjective-Cを比べると、他にも「列挙型の改善」「ジェネリクスの追加」など、多くの面で便利になっています。一方で、便利な面が増えただけではなく、ヘッダーファイルが廃止されたり、importが不要になったりと多くの改善があったので、高い生産性を実現できるかと思います。
移行は、可能なら全てのファイル一気に置き換えるのがベストです。しかし複数人が同時に開発している場合や、機能追加などの予定が決まっている場合など、一気に変更するのは難しいときもあるでしょう。そういった場合のために、今回は少しずつ変更していく手順をお伝えします。
SwiftとObjective-Cはプロジェクト内で共存することが可能です。ファイル単位で移行できるので、まずは1ファイルだけ移行してその後徐々に移行するとスムーズにいきます。
例として下図のようなシンプルな「MyApp」アプリを移行してみます。
まずは、「DetailViewController」をSwiftにしてみたいと思います。
SwiftとObjective-Cで同名のファイルを作成できるので、下図のように「DetailViewController」というファイル名でSwiftのファイルを作成します。
初めてSwiftファイルを作る場合は「bridging header」を作るかどうか聞かれるので「Yes」を選択しておきます。そうするとプロジェクト内に「{ProjectName}-Bridging-Header.h」という名前のファイルが生成されます。このファイルはSwiftからObjective-Cのファイルを呼ぶためのものです。詳しい使い方は後ほど説明致します。
下図のようにObjective-Cの「DetailViewController.m」ファイルのソースコードをSwiftへ移植します。
この際の注意点ですが、Swiftで「setDetailItem」のようなプロパティのセッターを上書きしたい場合はset/get構文を利用します。今回の場合は値の代入後にメソッドを呼ぶだけだったのでsetではなく「didSet」構文を利用しました。
次に、MasterViewController.mからSwift版のDetailViewControllerを呼びます。その際、「DetailViewController.h」と「DetailViewController.m」は削除してしまいます。
Swiftのコードを呼びたい場合は下図のように「{アプリ名}-Swift.h」というファイルをインポートします。今回はアプリ名が「MyApp」なので「MyApp-Swift.h」というファイルをimportしています。
最後にStoryboardを修正します。「DetailViewController.m」を消したことで、「Module」が「None」になっているかと思いますので、そこを「Current」に直します。
次に、IBOutletのひも付けをすればStoryboardの設定は完了です。
なお、SwiftからObjective-Cを呼ぶ方法も紹介しておきます。SwiftからObjective-Cを呼びたい場合は、先ほど作成した「{ProjectName}-Bridging-Header.h」を使います。
まずは、このファイルの中でSwiftから呼び出したいObjective-Cのファイルをimportします。そうすると、importしたファイルのObjective-CのクラスをあたかもSwiftのクラスのように呼び出せるようになります。
Objective-Cで書かれたCocoaPodsのライブラリを呼ぶ場合も同様の方法が使えます。
これで一つのファイルの移行ができました。以降は同じようにして1ファイルずつSwiftに移行していけば良いかと思います。
ここからは移行の際に気を付けることを紹介します。移行の途中でObjective-CとSwiftの共存させる場合の注意点です。
上記の例ではスムーズに移行できましたが、実際はSwiftでは使えないものもあります。その中で一番大きいものはマクロかと思います。
Swiftではマクロを定義できません。そのため、もしSwiftでマクロのようなことを実現したい場合は、どこかのクラスにstatic変数を定義する必要があります。
すでにObjective-Cファイルで定義されたマクロについては、Swiftでも一部だけ使うことができます。文字列やプリミティブ型については呼び出せますが、それ以外のクラスを定義していたり引数があったりすると呼び出すことができません。
#define MACRO1 1 // Swiftから呼び出せる #define MACRO2(a) 1 // 引数付きマクロはSwiftから呼び出せない #define MACRO3 MasterViewController // 文字列以外のクラスはSwiftから呼び出せない
大きい点としては列挙型と構造体があります。Swiftの列挙型と構造体はObjective-Cに比べて機能が追加されて使いやすくなっています。しかし、その影響のためか、Objective-CからはSwiftの列挙型と構造体を呼び出すことができません。そのため、Objective-Cでも呼ばれることが多いSwiftクラスでは列挙型と構造体を極力控える必要があります。
また、ジェネリクスやInt、Floatのオプショナル型を引数や返り値に設定しているSwiftのメソッドはObjective-Cからは呼び出すことができません。
この辺りはいざ呼び出すまでは気が付かないことが多く、気が付いたときには開発が進んでいて変更困難になりがちです。そのため、Objective-Cから呼ばれることが多いSwiftクラスの実装では極力、これらを意識しながら開発をすると良さそうです。
SwiftからObjective-Cのメソッドを呼び出す際も注意する必要があります。前述の通り、Objective-CはSwiftと違って変数にnilが入ることがあります。そのため、Objective-Cのメソッドは「一見オプショナル型ではない(nilを含まない)ように見えますが実はnilが入っている」ということがあります。
実行時にならなければ気が付かないエラーが増えるので、Objective-CとSwiftが混在する箇所は重点的に検証をする必要があります。
以上、本稿ではSwiftへの移行について紹介してきました。
SwiftとObjective-Cの混在時は上記のような問題がありますし、Objective-CとSwiftを両方触ることによって開発者が頭を切り替えるコストも掛かります。そのため、Swift化が決定した場合は、できるだけ素早く移行する計画を立てて短期間で行う方が良いでしょう。
移行への問題点は、いろいろありますが、Swiftは短くシンプルに書けるので使っていてとても楽しいプログラミング言語です。皆さまも、ぜひSwiftで楽しいiOSアプリ開発を実現してみてはいかがでしょうか。
田町のベンチャーで働くエンジニア。
仕事ではiPhoneアプリの開発やRailsを使ったWebサービス開発を行っている。最近のマイブームはUnityを使った3Dゲーム開発。
Copyright © ITmedia, Inc. All Rights Reserved.