ViewController インスタンスを Storyboard から取得する extension

  • 1
    Like
  • 1
    Comment

StoryboardからViewControllerのインスタンスを得る仕組みとして <#クラス#>.fromStoryboard() という共通のAPIにまとめてみました。

macOS

NSViewController.swift

import Cocoa

protocol StoryboardInstantiatable: class {

    /*
    継承クラスで以下を定義してください
    typealias StoryboardInstantiatableViewController = <#YourViewController#>
    static var storyboardName: String {
        return "<#Storyboard Name#>"
    }
    */

    associatedtype StoryboardInstantiatableViewController: NSViewController

    /// Storyboard 名を返す
    static var storyboardName: String {get}
    /// Initial View Controller をロードするには nil を返す
    static var storyboardID: String? {get}

    static func fromStoryboard(withStoryboardID storyboardID: String?) -> StoryboardInstantiatableViewController
    static func fromStoryboard() -> StoryboardInstantiatableViewController

}

extension StoryboardInstantiatable where Self: NSViewController {

    static var storyboardName: String {
        return "Main"
    }

    // デフォルト実装では View Controller 名を ID として返す
    static var storyboardID: String? {
        return "\(self)"
    }

    static func fromStoryboard() -> StoryboardInstantiatableViewController {
        return fromStoryboard(withStoryboardID: self.storyboardID)
    }

    static func fromStoryboard(withStoryboardID storyboardID: String?) -> StoryboardInstantiatableViewController {
        let sb = NSStoryboard(name: storyboardName, bundle: nil)

        if let storyboardID = storyboardID {
            return sb.instantiateController(withIdentifier: storyboardID) as! StoryboardInstantiatableViewController
        }
        else {
            return sb.instantiateInitialController() as! StoryboardInstantiatableViewController
        }
    }

}

使い方:Storyboard名のみを指定

typealiasとStoryboard名が必須です。
Initial View Controller、あるいはクラス名のStoryboard IDで自動判定します。Storyboard側でクラス名と同じものをStoryboard IDとして設定しておきましょう。

Storyboard名のみを指定

class ViewController: NSViewController, StoryboardInstantiatable {

    typealias StoryboardInstantiatableViewController = ViewController
    static var storyboardName: String {
        return "MyStoryboardName"
    }

}
呼び出し
let vc = ViewController.fromStoryboard()

使い方:Storyboard名とStoryboard IDを指定

特定のStoryboard IDでインスタンスを得ます。IDが不正だとクラッシュします。

Storyboard名のみを指定

class ViewController: NSViewController, StoryboardInstantiatable {

    typealias StoryboardInstantiatableViewController = ViewController
    static var storyboardName: String {
        return "MyStoryboardName"
    }
    static var storyboardId: String? {
        return "UltraViewController"
    }

}
呼び出し
let vc = ViewController.fromStoryboard()

使い方:Storyboard名とInitial View Controllerを指定

Storyboard IDでnilを返すとInitial View Controllerのインスタンスを得ます。うまく設定されていなければクラッシュします。

Storyboard名のみを指定

class ViewController: NSViewController, StoryboardInstantiatable {

    typealias StoryboardInstantiatableViewController = ViewController
    static var storyboardName: String {
        return "MyStoryboardName"
    }
    static var storyboardId: String? {
        return nil
    }

}
呼び出し
let vc = ViewController.fromStoryboard()

iOS

使い方は基本的に同じ。

UIViewController.swift
import UIKit

protocol StoryboardInstantiatable: class {

    /*
    継承クラスで以下を定義してください
    typealias StoryboardInstantiatableViewController = <#YourViewController#>
    static var storyboardName: String {
        return "<#Storyboard Name#>"
    }
    */

    associatedtype StoryboardInstantiatableViewController: UIViewController

    /// Storyboard 名を返す
    static var storyboardName: String {get}
    /// Initial View Controller をロードするには nil を返す
    static var storyboardID: String? {get}

    static func fromStoryboard(withStoryboardID storyboardID: String?) -> StoryboardInstantiatableViewController
    static func fromStoryboard() -> StoryboardInstantiatableViewController

}

extension StoryboardInstantiatable where Self: UIViewController {

    static var storyboardName: String {
        return "Main"
    }

    // デフォルト実装では View Controller 名を ID として返す
    static var storyboardID: String? {
        return "\(self)"
    }

    static func fromStoryboard() -> StoryboardInstantiatableViewController {
        return fromStoryboard(withStoryboardID: self.storyboardID)
    }

    static func fromStoryboard(withStoryboardID storyboardID: String?) -> StoryboardInstantiatableViewController {
        let sb = UIStoryboard(name: storyboardName, bundle: nil)

        if let storyboardID = storyboardID {
            return sb.instantiateViewController(withIdentifier: storyboardID) as! StoryboardInstantiatableViewController
        }
        else {
            return sb.instantiateInitialViewController() as! StoryboardInstantiatableViewController
        }
    }

}