Xcode
iOS
Storyboard

StoryboardのBestPracticeについて考える(1) 〜Storyboardの分割〜

Storyboardが導入される以前からiOSアプリ開発をしていた筆者にとって、
Storyboardは長らく敬遠しがちであった。

というのも、Storyboardを使うにあたってのデメリットが多く見受けられたからだ。
これは、Storyboardを使ってiOSアプリ開発を経験したことがある多くの同胞が
同様に感じたことだろう。

まずは、Storyboardのデメリットに関して、要点をいくつか挙げてみよう。

  1. Storyboardの肥大化
    画面数が多い、各画面における要素数が多い、またそれぞれの画面が複雑に遷移するようなアプリになると、Stroyboard自体が膨大になりまさにスパゲッティの様相になる。こうなると、Storyboardを綺麗に保つのは困難だし、把握するのも一苦労だ。そもそも、Storyboardを開くのにも時間がかかるようになり見るのも億劫になってくる。

  2. チーム開発に不向き
    1つのStoryboardで複数の開発者が作業していると必ずConfrictが起きる。StoryboardはXMLファイルとして確認することができるが、とてもじゃないが容易にMergeできるようなものではない。 同様に、Storyboardのコードレビューもほぼ不可能である。Storyboardを使い慣れていない開発者は、結構な確率で操作ミスなどでStoryboard上でバグを作るが、それに気づくことも容易ではない。

  3. 汎用性, 柔軟性に欠ける
    ビューの再利用やマクロの利用がしにくい。また、オブジェクトの型変更の対応も容易ではない。つまり、リファクタリングも手軽にできなくなる。

  4. コンパイル時に問題が検出できない
    Storyboardで設定したIDや、OutletやActionの接続ミスなどはコンパイルではエラーにならず、実行時に落ちてしまう。

Storyboardのデメリットとしてよく挙げられる、ないしは筆者が致命的だと思った点を挙げてみたが、これだけでも『Storyboardよ、さようなら』というタイトルで記事を書いたほうがいいのではないかとすら思えてくる。

ただ、AppleとしてはStoryboardの使用を推奨しているし、昨今の『iOSアプリ開発?Swift×Storyboard がデフォでしょ?』的な風潮に抗い続けるのもどうかと思い、なんとかStoryboardを快適に使用する手段がないかと模索した結果を記事することにした。

Storyboardの分割

先に挙げた"1. Storyboardの肥大化"と"2. チーム開発に不向き"の解決策として、"Storyboardの分割"による最適化を提案する。

1つのプロジェクトに対して1つのStoryboard(プロジェクト作成時にできるものでいうと"Main.storyboard")でアプリ内におけるすべての画面を管理するのが一般的である。この場合のStoryboardをみてみると、画面遷移の関係性が機能ごとに一括りになっているケースが多いことに気づくはずである。

スクリーンショット 2017-11-09 21.13.41.png

そして、チーム開発をする場合、機能ごとに担当を分担して作業をすることがほとんとである。つまり、Storyboardを機能ごとにわけることができれば、"Storyboardの肥大化"という問題と"チーム開発に不向き"という問題の2つを解決できるということである。

Storyboard Reference

Storyboard ReferenceはXcode7から追加されたUIコンポーネントの1つである。Storyboard Referenceを利用することで、Storyboardの分割は容易に実現できる。では、実際にやってみよう。

まずは、大きな機能ごとにそれぞれStoryboardを用意する。
たとえば、タブバーアプリケーションにおいては、各タブごとに機能が一括りになっているケースが多いので、各タブごとにStoryboardを用意するのがいい。

スクリーンショット 2017-11-09 21.53.24.png スクリーンショット 2017-11-09 21.56.30.png

Main.storyboardから用意した各Storyboardに、機能に属する画面を移動させる。

ここで忘れてはならないのが、このStoryboardにおいて最初に表示させるビューの"Is Initial View Controller"にチェックを入れることである。

スクリーンショット 2017-11-09 22.18.40.png

Main.storyboardにはUITabBarControllerのみを残し、UIコンポーネントからStoryboard Referenceを選択し、用意したStoryboard分配置する。配置したStoryboard Referenceにそれぞれ用意したStoryboardファイルを設定し、TabBarControllerのviewControllersとしてリレーションさせる。同様に、Segueを用いてStoryboard Referenceを"Show"や"Present Modally"で遷移させることができる。

スクリーンショット 2017-11-09 22.32.34.png

終わりに

いかがだっただろうか。すべての画面を1つのStoryboardに押し込んでいたときと比べると、断然すっきりとしたStoryboardになったのではないだろうか。また、このファイル構成であればチーム開発時にも、StoryboardでConfirictが起きる可能性を随分減らすことができるようになったのではないだろうか。さらに、UI上で問題が起きた場合でも、原因の切り分けが大分しやすくなっているはずである。
『すべての画面を1つのStoryboardで管理するから意味があるのだ!!』という声が聞こえなくもなかったが、実際に筆者はこの方法を用いて中規模アプリを開発し、これならば大規模アプリ開発でも問題なく戦えると自信を持って言える。また、こういった工夫を試行錯誤することで、Storyboardパイセンと少しだけ仲良くなれた気がするので、Storyboardに苦手意識を持ってる同胞には是非試していただきたいと思う。