暗黙的アンラップ型（Implicitly Unwrapped Optional）をいつ使うべきか？


仕事でSwiftのコードをよくレビューするのですが、どうやら暗黙的アンラップ型（Implicity Unwrapped Optional）をいつ使うべきか迷う方が多いようです。

_以下、文中では「暗黙的アンラップ型」で表記を統一します。また、`Optional.None`は`nil`という表現で統一します。説明を簡潔にするために一部正確でない表現をしている箇所があります。_

# 復習
暗黙的アンラップ型は、 **Optional型だけれど、アクセスするときには明示的なアンラップがいらない（強制的にアンラップされる）型** です。

以下のように`!`を型の後ろにつけて宣言します。

```swift:暗黙的アンラップ型のコード
var foo: String! = "Hello"
print(foo.lowercaseString) // hello
```

これは以下のコードと等価です。

```swift:Optional型のコード
var foo: String? = "Hello"
print(foo!.lowercaseString) // hello
```

つまり、暗黙的アンラップ型は以下の特徴を持っています。

- 実体はOptional型
- 変数にアクセスするときに強制的にアンラップされる。（`!`や`if-let`を用いたアンラップが不要）

# 注意点
前述の"Optional型のコード"を見れば分かるとおり、変数アクセス時に強制的にアンラップ（`!`）されるので、 **変数にアクセスした時に`nil`が入っていた場合はクラッシュする**という点に注意が必要です。

例えば、以下のコードはクラッシュします。

```swift:暗黙的アンラップ型にアクセスした時にnilが入っていた場合
var foo: String! = nil
print(foo.lowercaseString) // クラッシュ！
```

つまり、逆に言えば実際にアクセスするときには`nil`でないことを **自分で**保証しなければならないということです。

この **自分で**というところがポイントで、（通常の）Optional型であればコンパイル段階で`nil`チェックを強制できるところを、暗黙的アンラップ型は半信半疑（これは`nil`じゃないよね・・・絶対に・・・？）で利用しなければならないということです。

# 中間考察
ふむ、どうやら暗黙的アンラップ型は **10億ドルの誤りと呼ばれるnull参照**の時代に逆戻りしているようにも見えてしまいます。

つまり、暗黙的アンラップ型の変数に **安全に**アクセスするコードは以下のようになるでしょう。

```swift
var foo: String! = nil
if foo != nil {
    print(foo.lowercaseString) // こんなはずじゃなかったのに・・・
}
```

Swiftは10億ドルの誤りと呼ばれる`null`（および`null`チェック）を無くすために、言語仕様としてOptional型を用意し、安全を謳ったのではなかったのでしょうか？

# 暗黙的アンラップ型は必要か？
さきほどの中間考察だと、どうやら暗黙的アンラップ型は非常に不利な立場に立たされているように見えます。

「暗黙的アンラップ型は本当に不要なのか？」

その答えは当然ながらNoで、あると便利なので言語仕様としてわざわざ用意されています。

# 便利である理由
暗黙的アンラップ型が便利である理由は、IBOutletのコードを読めば理解できると思います。

以下は`UIButton`をIBOutlet接続した例です。

```swift:IBOutlet
@IBOutlet weak var button: UIButton!
```

見てのとおり暗黙的アンラップ型が使われています！

Optional型でも良かったかもしれませんが、その場合はアクセスする際に毎回アンラップする必要が発生します。

```swift:IBOutletがOptional型だった場合
@IBOutlet weak var button: UIButton?
if let btn = button {
    btn.backgroundColor = UIColor.redColor()
}
```

これはいささか面倒ですね、なぜって **絶対に値が入っていることが分かっているのにアンラップが必要になってしまう**わけですから。

お、何やら少し見えてきましたね。

# 次の疑問
さて、そうすると次の疑問が湧いてきます。

「絶対に値が入っていることが保証されるIBOutletが、なぜ`nil`が入る可能性のある暗黙的アンラップ型で宣言されているのか？」

だってそうでしょう、絶対に値が入っているならそもそもOptionalである必要は皆無のはずです。

しかし、Optionalを使わないようにコードを書き換えてもコンパイルエラーとなります。

```swift:IBOutletをOptionalにしないとコンパイルエラー
@IBOutlet weak var button: UIButton // 末尾の?を削除

// 以下のコンパイルエラーとなる
// @IBOutlet property has non-optional type 'UIButton'
```

これはどういうことかというと、 **Optional型でない以上、インスタンスが生成されたタイミングで値が入っていなければならないけれど、Swiftのイニシャライザ（つまりインスタンス生成時）では値が確定できないため**です。

なぜなら、StoryboardまたはxibからViewControllerが生成される仕組みは、Swiftの通常のインスタンス生成の仕組みからは外れたものだからです。

# 暗黙的アンラップ型をいつ使うべきか？
ようやくタイトルへと回帰できました。

・・・といっても答えはすでに出ているようなものですね。

暗黙的アンラップ型は、 **Swiftのインスタンス生成の仕組みから外れているけれど、実際にインスタンスが利用できるようになったタイミングでは必ず初期化されていることが保証できる変数**に対して使うべきでしょう。

その最たる例がIBOutletですが、Storyboardからインスタンスを生成したあとに確実に初期化する変数に利用するのもありだと思います。

```swift:確実に初期化される値における暗黙的アンラップ型の活用
var message: String! // create()で確実に初期化されるので利便性を考えて暗黙的アンラップ型で宣言

class func create(message: String) -> ViewController {
    let storyboard = UIStoryboard(name: "foo", bundle: nil)
    let viewController: ViewController =
    	storyboard.instantiateInitialViewController() as! ViewController
    viewController.message = message // 初期化
    return viewController
}
```

といっても上記の例であっても`message`の初期化が漏れればクラッシュするわけで、絶対に安全というわけには行きません。ですので、この辺りはさじ加減かと思います。

個人的にUIViewControllerにおいては、 **viewDidLoad以降であれば確実に値が入っていなければならない**変数については暗黙的アンラップ型を適用して良いと感じています。

# 利用の手引
これまでの議論を踏まえて、定数・Optional型・暗黙的アンラップ型の使い分けを考えると以下の順で考えていくと良いかと思います。

1. 定数
2. Optional型
3. 暗黙的アンラップ型

まず **インスタンス生成時に値が確定できるのであれば「1.定数」**を使うべきでしょう。

次にインスタンス生成時に値が確定できない、つまり **アクセスするときに`nil`である可能性がある場合は「2. Optional型」**を使うべきでしょう。

そして最後に、「2. Optional型」を適用したけれど、 **変数にアクセスするときには`nil`でないことが保証できる特別なケースにおいて「3.暗黙的アンラップ型」の適用**を考えましょう。

# まとめ
- 暗黙的アンラップ型の実体はOptional型
- 暗黙的アンラップ型にアクセスするときは強制アンラップ（`!`）される
- IBOutletとかで使われている
- インスタンス利用時に必ず初期化されることが保証できる場合に暗黙的アンラップ型を使うと便利
- 定数、Optional型、暗黙的アンラップ型、の順で適用を考えると良い（かも）
- ご利用は計画的に

# P.S.
個人的には（Javaのような）厳格で一貫性のあるコードよりも書きやすいコードを目指している（ように見える）Swiftに暗黙的アンラップ型を用意したのは良い判断だと感じています。

・・・むしろ必然？