「Refactor to Storyboard」で一定のフローをひとつのStoryboardとしてまとめておくと便利


Xcode7から使えるようになったStoryboard Referenceを使うとコードを書かずにStoryboard間の参照ができるようになりました。

既にStoryboard内にあるViewControllerからStoryboard Referenceを作る時の流れは、
1. 別のStoryboardに分けたいViewControllerを選択(複数選択可)
2. Editor > Refactor to Storyboard... を選択
3. ダイアログに従ってStoryboardファイル作成

です。

参考
Refactoring Storyboards

Storyboard Referenceを使ってStoryboardをキレイに

今までゴチャゴチャしていたStoryboardファイルが

Storyboard Referenceを使うことでSegueの接続でStoryboard同士を連携することができるようになり、簡単にキレイに保つことができるようになりました。

Storyboardに切り出す時に使うRefactor to Storyboard...を使えば ひとつのフローをそのままひとつのStoryboardとして切り出す というようなこともできます。

Storyboard Referenceを使った時のビルドエラー

便利だなーと思ってRefactor to Storyboard...でStoryboard Referenceを作っていると、ビルドエラーになることがありました。

Storyboard Referenceは基本的にはDeployment Target iOS 8.0から使えるのですが、iOS 9.0以前のバージョンだとビルドエラーになる場合があります。

「Storyboard References cannot be the destinations of relationship segues prior to iOS 9.0」とビルドエラーが出た時の対処法

「relationship segueで繋ぐ先にStoryboard Referenceを指定するにはiOS 9.0以上じゃないとダメだよ」っていうようなエラーなのですが、具体的にはTabBarControllerやNavigationControllerから直接Storyboard Referenceを繋げると起こります。

せっかく別のStoryboardに分けたフローはそのまま残しておきたいので、Storyboard Referenceを使わずにコードでStoryboardを呼び出すように変更します。

TabBarControllerの場合

Storyboard上で繋がっていたStoryboard Referenceを削除し、UITabBarControllerだけにします。
Refactor to Storyboardで作ったStoryboardファイル自体は残しておきます。

コードではUITabBarControllerを継承したクラスを作り、UITabBarControllerのviewControllersを指定します。

class TabBarController: UITabBarController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let firstViewStoryboard = UIStoryboard(name: "FirstView", bundle: NSBundle.mainBundle())
        let secondViewStoryboard = UIStoryboard(name: "SecondView", bundle: NSBundle.mainBundle())

        let firstViewController = firstViewStoryboard.instantiateInitialViewController()
        let secondViewController = secondViewStoryboard.instantiateInitialViewController()

        self.viewControllers = [firstViewController!, secondViewController!]

        // Do any additional setup after loading the view.
    }

}

UITabBarControllerではStoryboard Referenceを使わなくなるので、先ほどのビルドエラーは解消され、Refactor to Storyboard...で作ったStoryboardファイルはそのまま使うことができます。

NavigationControllerの場合

NavigationControllerでも同じようにコードで、UINavigationControllerのviewControllersを指定します。

class NavigationController: UINavigationController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let navigationStoryBoard = UIStoryboard(name: "Navigation", bundle: NSBundle.mainBundle())
        let navigationViewController = navigationStoryBoard.instantiateInitialViewController()

        self.viewControllers = [navigationViewController!]
    }

}

さいごに

「設定画面のStoryboard」や「チュートリアル画面のStoryboard」のように、 一定のフローをひとつのStoryboardとしてまとめておく とフロー自体をそのまま別アプリでも再利用できるので便利です。

個人で作ったみんなのリストというアプリの開発時には、メインアプリとは別にチュートリアルだけの小さなプロジェクトファイルを作って、ある程度できた段階でStoryboardごとメインアプリの方に移したりしていました。