storyboard とのつきあい方


はじめに

iOSアプリを作る際に storyboard はどうするのか?というのが悩みどころです。色々なところで議論されてますが storyboard について自分なりにまとめてみました。

方法

  1. Main.storyboard に全てのせる
  2. storyboard は使わない
  3. Main.storyboard + xib
  4. 機能ごとに storyboard を分ける
  5. 1画面1storyboard

Main.storyboardに全てのせる

とりあえず何も考えずに Main.storyboard に全画面のせちゃえってやつです。

やり方

利点

  • 一目で画面遷移がわかる
  • storyboard で色々設定できるのでコード量が減る

欠点

  • 画面が増えてくると storyboard を開くのに時間がかかる
  • 複数人開発の場合 storyboard でコンフリクトが頻発する

たまに40画面くらい全部のせとかいうプロジェクトもみましたが、間違って storyboard を開いてしまった時はイライラします。この方法は数画面程度の小さいアプリかつ開発者は1人の場合とかならやってもいいかなという感じです。

storyboard は使わない

もう storyboard とか嫌や!消しちゃえってやつです。

やり方

  1. Main.storyboard を削除
  2. プロジェクト設定 → Info → Main storyboard file base name の値削除
  3. AppDelegate で rootViewController を設定
  4. 画面のレイアウトは xib でやる

rootViewController の設定

AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        window = UIWindow(frame: UIScreen.main.bounds)
        window?.rootViewController = UINavigationController(rootViewController: FirstViewController())
        window?.makeKeyAndVisible()
        return true
    }

遷移処理

FirstViewController.swift
    @IBAction private func tappedSecond(_ sender: UIButton) {
        let vc = SecondViewController()
        self.navigationController?.pushViewController(vc, animated: true)
    }

    @IBAction private func tappedThird(_ sender: UIButton) {
        let vc = ThirdViewController()
        self.present(UINavigationController(rootViewController: vc), animated: true, completion: nil)
    }

利点

  • コンフリクトが減る

欠点

  • ぱっと見で画面遷移がどうなっているかわからない
  • storyboard の恩恵を受けれないのでコード量は増える

途中参加したプロジェクトだと画面遷移を把握するのに多少苦労しますが、この方法はメンバとの話し合い次第でありかなと思います。(ちゃんと遷移図とかの資料があれば画面遷移も把握できます。資料があれば...)

storyboard は逆に色々設定でき過ぎてこの設定どこでやってんねん!てなる場合はオススメ。

Main.storyboard + xib

storyboard は使いたい!けどレイアウト触るたびにコンフリクトは嫌や!ってやつです。

やり方

  1. Main.storyboard に ViewController をのせ View を剥がす。
  2. xib を作成し、レイアウトを組む

遷移処理

FirstViewController.swift
    @IBAction private func tappedSecond(_ sender: UIButton) {
        self.performSegue(withIdentifier: "toSecond", sender: nil)
    }

    @IBAction private func tappedThird(_ sender: UIButton) {
        self.performSegue(withIdentifier: "toThird", sender: nil)
    }

利点

  • Main.storyboard を見れば画面遷移がなんとなくわかる
  • storyboard で色々設定できるのでコード量が減る(containerView とかは使えない)
  • コンフリクトが減る

欠点

  • Main.storyboard だけ見てもぱっと見でどこの画面かわからない
  • xibでレイアウトを組むので containerView とか使えない
  • 画面の生成方法に注意しないとバグる(下記参照)

下記のように画面生成されるとレイアウトはそのままですが storyboard の設定がなくなってしまいます。

let vc = FirstViewController()

この方法なら segue も使えるし、コンフリクトも起きにくいのでわりといい気がします。ただ、storyboard の恩恵が一部得られません。

機能ごとに storyboard を分ける

Main.storyboard に全部置くのはアレなんで機能ごとに分けちゃえってやつです。

やり方

  1. Main.storyboard を削除する。
  2. ログイン機能、検索機能など機能ごとに storyboard を作成する
  3. プロジェクト設定 → General → Deployment Info の Main Interface に初期表示の storyboard を設定する
  4. storyboard 間の遷移は Storyboard Reference を使う

利点

  • storyboard を見ればなんとなく遷移がわかる
  • 機能ごとに分かれてるので見やすいといえば見やすい
  • storyboard で色々設定できるのでコード量が減る
  • コンフリクトが多少減る

欠点

  • 遷移を追うには色々な storyboard を見ないといけない
  • やっぱりコンフリクトが起きる
  • どこの機能に入れればいいかわからない画面が出てきて storyboard が増える(終いには Other.storyboardとか出て肥大化する)
  • 一部機能の画面が増えてくると storyboard を開くのに時間がかかる

この方法は正直中途半端な感じがして嫌いです。

1画面1storyboard

xib とかナンセンス!完全上位互換の storyboard 使っちゃえってやつです。

やり方

  1. Main.storyboard を削除する。
  2. 画面ごとに storyboard を作成する
  3. プロジェクト設定 → General → Deployment Info の Main Interface に初期表示の storyboard を設定する
  4. storyboard 間の遷移は Storyboard Reference を使う

利点

  • storyboard を見ればなんとなく遷移がわかる
  • storyboard で色々設定できるのでコード量が減る
  • コンフリクトが減る

欠点

  • 遷移を追うには色々な storyboard を見ないといけない

この方法が一番いいんじゃないのかなと思います。segue も containerView も使えるし、コンフリクトも起きにくいです。ただこの方法で実装したことがないので思わぬ欠点があるかもしれません。

xib より storyboard がいい点

今までは Main.storyboard + xib でやってたのですが1画面1storyboard の方がいいじゃないかなと思い、xib より storyboard がいい点についてまとめます。

TableView の設定が色々できる

iPhone アプリの画面で多いのが tableView をのせただけの画面が多いと思いますが、xib の場合ぱっと見なんの画面かわかりません。

storyboard の場合だとセルやヘッダーフッターをのせたりできるので一目でどの画面かわかります。(セルを他の画面でも使いまわしたい場合は xib でセルを作る方がいいと思いますが...)

ContainerView が使える

複雑な画面で部品を他クラスで分割したい場合も xib の場合ぱっと見なんの画面かわかりません。
例えば上に tableView 下に collectionView を置きたい場合。xib だと上下の View にカスタムクラスを設定してそれぞれ別で xib を作成するか、別で xib で ViewController を作成しコード上で上下の View に addSubView して childViewController の設定をしなければいけません。

storyboard の場合だと storyboard 上で設定できるし、見た目もわかりやすいです。

storyboard の 問題点

その他 storyboard 利用時の問題点についてです。

id のタイポ問題

storyboard の segue や Storyboard ID, セルの identifier などのタイポ問題。performSegue(withIdentifier: "id", sender: nil) などの利用時に id をタイポしていると実行するまでなかなか気づくのが難しいです。この問題は R.swift を使えば解決です。

preparefor segue の肥大化

画面遷移時に値を渡したい場合 func prepare(for segue: UIStoryboardSegue, sender: Any?) で処理するので画面が増えるとどんどん処理が肥大化していき見通しが悪くなります。switch とかで処理を分岐して細かくメソッド分けるしかないかなと思います。

さいごに

結論としては1画面1storyboard で R.swift を使うのがいいんじゃないかなと思います。この辺はまた Swift UI でガラッと変わるのかもしれませんが今のとこは1画面1storyboard 推しです。

いいんじゃないかなと思いますが、この方法やったことないので思わぬ欠点があるかもしれません。また、こんな方法もあるよってのがあればどなたか教えていただけたら幸いです。