Interface Builderに依存しないiOS開発のススメ

eureka, Inc.
Eureka Engineering
Published in
10 min readDec 22, 2017

--

この記事はeureka Native Engineer Advent Calendar 2017 22日目の記事です。
21日目の「Swift Package Manager V4 + Utilityで作る!コマンドラインツール」に続き、本日も@satoshin21が担当させて頂きます。

Interface Builderに依存しないiOSアプリ開発

皆さんは、普段iOSアプリケーションを開発する上でUI周りはどのように開発していますか?
Pairs JPのiOSチームでは新規で画面を実装する場合、StoryboardやXib/Nibを作らずにほぼ全てのUIをコード上で実現しています。
既存の画面についても少しづつ手を加え、Interface Builderからの脱却を進めています。
今回は、我々がなぜStoryboardやXib/Nibを使わない決断をしたのか、Interface Builderのメリット・デメリットの観点から説明します。また、Interface Builderを使うべき場面についても説明します。

以降、便宜上によりStoryboard、及びXib/NibファイルをIBファイルと呼びます。

チーム開発 × IBの相性

我々がまず課題として挙げたのが、チーム開発とInterface Builderの相性です。

Pairs JP iOSの開発チームはすべての部門を合わせると7, 8人の体制です。
GitHubのPRをベースに1~2人のレビュアーをアサインし、コードの妥当性、検証を行ってからプロダクトへマージするフローとなっています。

そこで問題になるのが、レビュアーのレビューコストをなるべく抑え、かつ正しくレビューできるようにするにはどうするべきか?という点です。
コードについては、都度チームメンバーでアーキテクチャについての情報共有を行い、コーディング規約を遵守することでコードの健全性を保つことができるかと思います。

しかし、IBファイルの場合はInterface Builderから生成される為、なかなか手を加える事ができません。
IBファイルの実態はXMLですが、Interface Builderから生成されたXMLファイルは人の目で正しく検証できるようなものではないと考えます。検証するには、一度Xcode上でInterface Builderを立ち上げ、GUI上で確認しなければならないかと思います。

一度GitHubを閉じて、Xcodeを立ち上げ、該当のIBファイルを開き、マージ先ブランチのIBファイルも開き、2つをならべてどのような変更があったのかを確認し、問題がある場合はGitHubで該当箇所にコメントを入れる・・・
IBファイル1つであればギリギリ許容できるレベルかなとも思いますが、複数のIBファイルやクラスファイルと照らし合わせて確認するとなると、レビュアーに対する負荷が高すぎます。

恐怖のコンフリクト地獄

我々の開発するPairsは今年で5年目を迎えました。
新機能の追加や、デザインのリニューアルを進めていくと何年も前の画面、コードに手を加え、新しい機能を追加することもしばしばあります。
IBファイルに手を加える事も多いのですが、その際複数人が同じIBファイルに対してコミットしていないかに気をつけなければいけません。

前述しましたが、IBファイルの差分は基本的に人による検証が難しいです。それはつまり、複数人が同じIBファイルに対して修正や追加を行った場合、お互いの差分を安全にマージすることが通常のコード差分のマージよりも難しいと思います。
上記のようなコミュニケーションを怠ると、IBファイルはしばしば盛大にコンフリクトが発生します。

UIパーツの再利用性

複数の画面を持つアプリを実装する場合、ここの画面のこのボタンをデザインそのままにこっちの画面に表示したい、という要件に対応することは多いかと思います。
コードで定義されている場合は移植は比較的簡単です。しかし、IBファイルに定義されている場合はどうでしょう。特に要件として多いのが、TableViewCollectionViewのCellを再利用する場合です。

Storyboard上のTableViewに直接Cellが定義されている場合、そのCellをそのまま別のViewControllerで使うことはできません。Storyboard上でCellをコピーして別IBファイルに移植すれば対応は可能ですが、その場合一つのUIクラスに対して複数のstoryboardが紐づくことになり、非常に危険です。

また、UIクラスの継承についても、Interface Builderと紐付いている場合とたんに設計が難しくなります。
IBで定義していたUIを親としてサブクラスを作成し新しくSubviewを追加する場合、同じようなIBファイルを複製してそれぞれのUIクラスに紐付けるか、もしくはサブクラス側でしか使用しないSubviewをIBファイル上に定義しておき、スーパークラスではそのViewを非表示にしておくなどの対応が必要かと思います。
私は、どちらにおいても未来の実装者に対して混乱させる要因となりうると思います。

仕様を集約させる

静的ページであれば、Interface Builderのみで画面を実装することができます。
ですが、昨今のiOS開発においてはそのようなアプリを実装する機会はほとんどないかと思います。
クラスファイルと紐付け、動的にテキストや色などを設定し、場合によってはアニメーションにより複雑なレイアウトを実現する必要があります。
IBファイル上でも各Viewのプロパティを定義することが可能ですが、その場合問題になるのが、IBファイルと実装ファイル、どちらにそのattributeを設定するかという課題です。

プロダクトをリリースするまでの初期フェーズでは、どちらに定義していようがそれほどインパクトはないかもしれません。
しかし、運用フェーズに入り、既存のViewに手を入れる必要が出てきた場合に実装者を混乱させる一つの要因になると思います。
IBファイル上で定義しておけば問題ない!と思ったら、クラス上で動的に変更していたために不具合が発生してしまったり
ここプロパティは変更してもいいものなのか、NSLayoutConstraintは変更しても問題ないものなのかなど、IBファイルと紐付いている場合にスコープはクラス全体に広がる為にすべてをチェックしなければならず、余計な負担を未来の実装者に与えることになります。

IBファイルはどのような時に利用すべきか?

Interface Builderを用いることについてのデメリットについてまとめました。
では、すべての場合においてiOS開発の時にコード上でUIをかくべきなのでしょうか?
私は、環境やサービスのフェーズによっては、Interface Builderを利用すべきと考えます。

とにかくいち早くプロダクトを形にしたい、もしくはプロトタイプを作りたい時

Pairsのようにサービスを世に送り出してから数年も経過したような場合は今後の継続的な開発に向けた対応が必要ですが、サービスがまだリリースされていない、もしくはサービスの黎明期においては、とにかくいち早くプロダクトをリリースしたい、早く機能を追加したいという場合があるかと思います。

Interface Builderの利点はそのUIの実現スピードの速さにあると思います。
コード上でUIを実現する為のサポートライブラリがいくつもあるとは言っても、ViewControllerの作成から各UIパーツの初期化、アクション時の処理、レイアウト(AutoLayout, etc)など、実現イメージを頭で思い浮かべながら作らなくてはなりません。
慣れていない場合は、都度ビルドし実機で画面を確認しつつすすめる必要があるかと思います。

その点Interface Builderで画面を定義する場合は、GUI上で画面の実現イメージを素早く確認しながらUIの開発が可能です。
仮にプロトタイプをXcodeで作成する場合などは静的な画面を定義するだけでよいので、場合によってはInterface Builderのみで実装することも可能です。

サービスの価値をいち早くユーザに提供したい、とりあえず実装イメージをいち早く確認したい時などはInterface Builderを用いることを検討すべきだと思います。

チームのiOS開発に対する習熟度が足りない時

ある程度iOSなどの開発に対する習熟度が高い、特にレイアウト周りについての知見が集まっている場合などはコードでレイアウトを定義する事を検討すべきです。
ただし、まだチーム全体のiOSの開発に対する知見(特にUI周り) が足りない場合には、無理にコードでUIを実装する必要はないと思います。

iOSにおけるUI周りの開発は、お作法のようなものがいくつか存在します。
NavigationController, TabBarControllerなどのContainerViewControllerの挙動についてもそうですし、ViewControllerのライフサイクルについても気を配らなければなりません。
また、AutoLayoutなどのレイアウト周りを習得するには、コード上だけで実装しているだけだと理解が難しい部分が多々出てくるかと思います。

Interface BuilderはGUI上のドラッグ&ドロップでUIを配置、AutoLayoutも比較的わかりやすいインターフェイスで実装することが可能です。
前述しましたが、レイアウトの結果をリアルタイムで確認しつつ実装を進めることによって、わかりにくいレイアウト周りの学習速度を早めることができるかと思います。

おわりに

iOS開発において、Interface Builderとの付き合い方についてご紹介させて頂きました。
IBはiOS開発の初学者にとって頼もしい味方となります。レイアウト周りについて最初はわかりにくい事も多いと思いますが、IBはiOS開発にとりまくとっつきにくさを軽減し、学習効率を高めてくれます。
ただし、ある程度レイアウト周りに慣れてきた時や、チーム開発による辛さを感じた場合は
IBに頼らないレイアウト方法についても目を向けることでより効率的、かつ安全にアプリを開発することができると思います。
ユーザにちゃんと価値を届ける為にも、UIの実装方法についてぜひ検討してみてください!

追記

こちらの記事の内容をよりTeam Developmentにフォーカスしてお話しようと思い、try! Swiftに提出していたCfP「World of No Interface Builder」は残念ながら非採択となってしまったのですが、try! Swift After Talkにてお声がけ頂いたため、登壇させて頂きました。

https://speakerdeck.com/satoshin21/world-of-no-interface-builder

懇親会でもUI構築についての様々な知見を交換する事ができ、とても有意義な時間を過ごすとともに、コードでレイアウトで書くことの関心の高さを肌で感じることができました。

より詳しい内容については、AKIBA.swift × エウレカ コードレイアウト勉強会でお話するつもりなので、是非とも起こし下さい!

https://classmethod.connpass.com/event/81032/participation/#waitlist

--

--

eureka, Inc.
Eureka Engineering

Learn more about how Eureka technology and engineering