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

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

# macOS

```swift: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として設定しておきましょう。

```swift:Storyboard名のみを指定

class ViewController: NSViewController, StoryboardInstantiatable {

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

}
```

```swift:呼び出し
let vc = ViewController.fromStoryboard()
```

## 使い方：Storyboard名とStoryboard IDを指定

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

```swift:Storyboard名のみを指定

class ViewController: NSViewController, StoryboardInstantiatable {

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

}
```

```swift:呼び出し
let vc = ViewController.fromStoryboard()
```

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

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

```swift:Storyboard名のみを指定

class ViewController: NSViewController, StoryboardInstantiatable {

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

}
```

```swift:呼び出し
let vc = ViewController.fromStoryboard()
```

# iOS

使い方は基本的に同じ。

```swift: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
		}
	}
	
}

```