UIStoryBoardにinstantiateInitialViewControllerメソッドをextensionで実装する

画面遷移時などでStoryBoardが切り替わる場合、initial、つまり最初に表示させるViewContorllerを設定しなければなりません。実行時エラーが生じる訳ではありませんが、これがなされていないと背景が真っ黒のUIWindowだけが呼び出されてしまい無意味です。インスタンスメソッドのinstantiateInitialViewControllerは、画面遷移時などStoryBoardをイニシャライズし、またinitial設定を行います。

このメソッドはStoryBoardの切り替えの際に必要となるケースが多いため、記述するシーンは少なくありません。今までは必要に応じて調べて対応していましたが、最近になってextensionで呼び出しやすいように実装されている方法を知りました。これでなにができるのかというと、その都度必要な場合にメソッドを記述する必要がなくなり、また予測で呼び出しやすくなります。1箇所にまとめられることで、コードも把握しやすくなります。

extensionの使い方としても、とても参考になりました。
ここではinstantiateInitialViewControllerメソッドの基礎的な理解を含めてまとめています。ここではextensionとプロパティ周りの用語の理解は行わず、必要と考えられる程度の記述に留めています。

#実装方法

```swift
extension UIStoryboard {
  static var sampleViewController: SampleViewController {
    UIStoryboard.init(name: "Sample", bundle: nil).instantiateInitialViewController() as! SampleViewController
  }
}
```

ここではextensionでUISroryboardクラスで呼び出せるようにしています。なぜUIStoryboardクラスなのかというと`.instantiateInitialViewController()`がすでに実装されているメソッドであるからです。extensionといっても、そのクラスに実装されていないメソッドを載せても利用できません。あるいは利用するなら実装し直す必要があります。もちろん、それでは本末転倒です。ちなみに、.initの前のUIStoryboardはselfとして記載しても同じです。

呼び出し方

```swift
//返り値はViewContorller
UIStoryboard.sampleViewController
```
コンピューテッドかつスタティックプロパティとして変数を宣言しており、クラスに紐づけられているため、呼び出し方は基本的には変わらないはずです。storyboardが増えてくると、その都度記述しなければならなかったメソッドもextensionでまとめると、とても綺麗なコードになります。

（と言ってワイは参考にしているだけなんやが）

#各定義
#instantiateInitialViewController

Instance Method
UIStoryboard > instantiateInitialViewController

```swift
func instantiateInitialViewController() -> UIViewController?
```

UIStoryboardクラスに属します。メソッドの名称から分かるように、返り値はUIViewControllerです。インスタンスメソッドはインスタンスがなければ利用できないため、記述例にあるようにinitでイニシャライズを行っています。


#UIStoryboard.init(name:bundle:)
```swift
class UIStoryboard : NSObject {

  init(name: String, 
  bundle storyboardBundleOrNil: Bundle?)

}
```
ドキュメントには`Creates and returns a storyboard object for the specified resource file.`とあるように、特定のファイルからStoryboardのオブジェクトを作成し返します。その際のパラメータは次のとおりです。

#１　Parameters
`name`
Storyboardのファイル名を、String型として記載して指定します。ファイルの拡張子名 .storyboard は不要です。例えば、Sample.storyboardであれば、"Sample"と記述すればよいわけです。

`storyboardBundleOrNil`
storyboardファイルやその関連したファイルを含むbundleを指定します。名称からわかるように、Storyboardのbundleか、もしくはnilを指定する形となっています。nilを許容しなければならないため、`Bundle?`とオプショナルになっているんですね。nilである場合は、現在のアプリケーションのmain bundleとして映るようです。

```swift
// Get the app's main bundle
let mainBundle = Bundle.main
```

例示されているように、Bundle.mainとして利用することができるようです。と調べて書いてきましたが、そもそもbundleとはなんでしょうか。

#そもそもBundleとは？

Google先生で調べてみると、製品をひとまとめにすること、付属していることを指してバンドルと言うのだそうですが、これではなんのことだろうかって感じです。

https://developer.apple.com/documentation/foundation/bundle

Appleのドキュメントは`A representation of the code and resources stored in a bundle directory on disk.`となっていて、ディスクにあるバンドルディレクトリの中に保持されているコードとリソースを表現したものとされていて、これもよくわからない。

ただもう少し追っていくと、`By using a bundle object, you can access a bundle's resources without knowing the structure of the bundle. `と書かれていて、バンドルの中の構造を知らなくても、オブジェクトを通して中身を利用することができるよんって書かれています。

つまり、実装したコードやリソースはバンドルの中にまとめられていて、それをオブジェクトを通じてアクセスできるわけです。拙い経験ですが、外部ライブラリなど使うとバンドルの利用機会は増えてくるように思われます。

実際にどのような時に利用するのかというと一般的なパターンとしては
・`Create a bundle object for the intended bundle directory.`
　意図されているバンドルディレクトリのオブジェクトを作る場合
・`Use the methods of the bundle object to locate or load the needed resource.`
　必要なソースの位置を指定したり読み込むためのbundleオブジェクトのメソッドを使用する場合
・`Use other system APIs to interact with the resource.`
　特定のソースと通信するために他のシステムのAPIを叩く場合
となっています。

#２　Return Value

返り値はstoryboardのオブジェクトです。マッチする名前のファイルが存在しない場合は、`: Could not find a storyboard named 'XXXXXX' in bundle....`としてエラーが表示されます。

# as! -ViewController 

型のダウンキャストを行なっています。冒頭のinstantiateInitialViewControllerメソッドの定義を見てみるとこのようになっています。

```swift
func instantiateInitialViewController() -> UIViewController?
```
返り値はUIViewControllerクラスのオプショナルであるため、ダウンキャストを行なっているものと考えます。素人考えではinitが成功するのであれば、なんとなく返り値は確定されているのでオプショナルにならないんじゃないかと思うのですが、どうなんでしょうか。

ここまでが具体的な実装の中身となります。