Protocolを利用してStoryboardやXibファイルからインスタンスを生成する

追記
[iOS - 構造体でStoryboardとNibを管理する - Qiita](http://qiita.com/rizumita/items/84f0e59998ae2c66cd12)の方が1箇所にリソースの定義をまとめられて分かりやすいかもしれません。

---

[Swift - StoryboardやXibファイルからインスタンスを生成するprotocol - Qiita](http://qiita.com/morizotter/items/f25bf03fa4e151703451)という記事を拝見して、そのProtocolを改造した。

```Swift
protocol Instantiatable {
    typealias InstanceType
    static func instantiateFromResource(resourceName: String?, identifier: String?) -> InstanceType!
}

protocol ResourceBundleProvider {
    static var resourceBundle: NSBundle { get }
}
extension ResourceBundleProvider {
    static var resourceBundle: NSBundle { return NSBundle.mainBundle() }
}

protocol StoryboardInstantiatable: Instantiatable, ResourceBundleProvider {
    typealias InstanceType = Self
    static var storyboardName: String { get }
    static var viewControllerIdentifier: String? { get }
}
extension StoryboardInstantiatable {
    static var storyboardName: String { return "" }
    static var viewControllerIdentifier: String? { return nil }
    static func instantiateFromResource(resourceName: String? = nil, identifier: String? = nil) -> InstanceType! {
        let name = resourceName ?? storyboardName
        let identifier = identifier ?? viewControllerIdentifier
        
        let storyboard = UIStoryboard(name: name, bundle: resourceBundle)
        if let identifier = identifier {
            return storyboard.instantiateViewControllerWithIdentifier(identifier) as! InstanceType
        } else {
            return storyboard.instantiateInitialViewController() as! InstanceType
        }
    }
}

protocol NibInstantiatable: Instantiatable, ResourceBundleProvider {
    typealias InstanceType = Self
    static var nibName: String { get }
}
extension NibInstantiatable {
    static var nibName: String { return "" }
    static func instantiateFromResource(resourceName: String? = nil, identifier: String? = nil) -> InstanceType! {
        let name = resourceName ?? nibName
        let nib = UINib(nibName: name, bundle: resourceBundle)
        return nib.instantiateWithOwner(nil, options: nil).first as! InstanceType
    }
}
```

## 使い方
### StoryboardInstantiatableの使い方
UIViewControllerをStoryboardInstantiatableに以下のように適合させる。storyboardNameというクラス変数にストーリーボード名を設定するだけ。instantiateメソッドにストーリーボード名を直接渡す場合はstoryboardNameは必要ない。

```Swift
class SampleViewController: UIViewController, StoryboardInstantiatable {
    static var storyboardName = "Sample"
```

インスタンスを得るには以下のようにする。instantiateにストーリーボード名を渡すと、そのストーリーボードが利用される。Storyboard名を渡すとstoryboardNameが設定されていても引数のStoryboard名が優先されて利用される。
Storyboard ID(引数名: identifier)を渡すと、instantiateViewControllerWithIdentifier(_)でインスタンス化が行われる。指定しないとviewControllerIdentifierクラス変数が利用される。引数でもクラス変数でもidentifierが指定されない場合はinstantiateInitialViewController()が利用される。

```Swift
let controller = SampleViewController.instantiateFromResource()
let controllerInOtherStoryboard = SampleViewController.instantiateFromResource("Other")
let controllerWithIdentifier = SampleViewController.instantiateFromResource("Other", identifier: "SecondViewController")
```

### NibInstantiatableの使い方
UIViewをNibInstantiatableに以下のように適合させる。nibNameというクラス変数にNib名を設定するだけ。ただし変数の型は明示する必要がある。Storyboardと同様にinstantiateメソッドにストーリーボード名を直接渡す場合はnibNameは必要ない。

```Swift
class SampleView: UIView, NibInstantiatable {
    static var nibName = "SampleView"
```

インスタンスを得るには以下のようにする。

```Swift
let sampleView = SampleView.instantiateFromResource()
let sampleViewOnOtherNib = SampleView.instantiateFromResource("OtherView")
```