Swiftのオプショナル型について

# オプショナル型とは
オプショナル型とはデータ型の一つで、変数の宣言時に使用します。
特徴としては変数に`nil`の代入を許可することで、逆に非オプショナル型は`nil`の代入を許可しないことになります。

`nil`とはデータが無い（変数が空の状態）を表します。

iOSでは`nil`に対して操作するとアプリケーションが落ちてしまうことがあり、そのような問題を解決するために`swift`では`nil`を基本的には許容しないとのことです。しかし、オプショナル型を使うことで`nil`を扱うことができるようになります。



# オプショナル型の使い方
```Swift
// オプショナル型
var age: Int? 
var name: String!

// 非オプショナル型
var age: Int 
var name: String
```
オプショナル型は最後に`？`か`！`をつけます。非オプショナル型は最後に何もつけません。
また、一般的にオプショナル型 ( Optional Value ) というと`？`、`！`は暗黙的アンラップ型  ( Implicitly Unwrapped Optional )と呼ばれるオプショナル型になります。

非オプショナル型の変数は普通に扱う変数で、`nil`を扱うことのできるオプショナル型の変数は通常とは扱い方が少し異なります。オプショナル型の変数を通常の変数と同様に扱おうとするとおもわぬエラーが起きるため、オプショナル型の値を通常の値に変換するアンラップという方法が必要になります。

#### 暗黙的アンラップ型
一般的なオプショナル型と違い、使用するとき必ず強制的にアンラップされます。利点として、初期値はないが後から必ず値を入れる保証があるものに使うと効果を発揮します。



# なぜアンラップが必要なのか？
まずは、オプショナル型と非オプショナル型の出力結果の違いを見ていきます。

```Swift
// オプショナル型
var name: String?
name = "Taro"
print(name)  // 出力結果 Optional("Taro")

// 非オプショナル型
var name: String
name = "Taro"
print(name)  // 出力結果 Taro
```

上記の通り、オプショナル型は __Optional("Taro")__ 、非オプショナル型は __Taro__ と出力されていることから大きな違いがあるとわかります。

また、__「Optional(値)」__と__「値」__は異なるもので、同様には扱うことができません。

```Swift
var a: Int? = 10 // オプショナル型 
var b: Int = 10 // 非オプショナル型
a + b
/* 
-> a + b はエラーとなる
Value of optional type 'Int?' must be unwrapped to a value of type 'Int'
オプションタイプ「Int？」の値 タイプ「Int」の値にアンラップする必要があります。
*/
```
結果はエラーとなり実行することができません。
なぜなら、`変数a`は __Optional(10)__ 、`変数b`は __10__ という値であるため、`Optional(10) + 10`は計算することができないということになります。  
ここで、オプショナル型の値を通常の値 ( `Optiona(10)`を`10` ) に変換するためにアンラップという処理が必要ということになります。



# アンラップとは
`Optional`は値を包み込むラップのようなイメージで、オプショナル型は値を`Optional`というラップで包み込んでいます。そうすると、たとえ中身がない ( `nil` ) 状態でも包み紙だけは存在するため、扱うことができます。  
しかし、この便利な包み紙があるために値はラッピングされ、直接扱うことができません。扱うためにはラップを取り除き、中身の値を取り出さなくてはいけません。この包み紙を取り除き、値を取り出すことをアンラップと言います。



# アンラップの種類
### 1. 強制的アンラップ
そのままの意味になりますが、`オプショナル型を強制的にアンラップする方法`です。オプショナル型の変数の中にどんな値が入っていても関係なく、その値を取り出します。

```Swift
var name: String?
name = "Taro"
print(name!)  // 出力結果 Taro
```
オプショナル型の変数に対して`!`をつけ強制的アンラップをすると、出力が`Taro`となりました。  
簡単に扱える強制的アンラップですが、アンラップする対象のオプショナル型の変数の中身が`nil`だった場合、エラーとなりアプリケーションが落ちてしまうという欠点があります。なので、強制的アンラップをする場合は、必ずラッピングの中身が存在する(`nil`ではない)ことが保証されていなければいけません。

### 2. オプショナルバインディング
強制的アンラップはオプショナル型の変数を中身の値に関係なくアンラップしました。そのため変数に`nil`が入ってしまうとアプリケーションが落ちてしまうという問題があり、それを解決するアンラップの方法がオプショナルバインディングです。  
オプショナルバインディングの特徴は条件式を用いることで、アンラップする対象のオプショナル型の変数が`nil`かどうかを判定するためのものです。

#### `if let`
* `nil`だった場合に行う処理が異なる時に使用します。
* `nil`の場合は__Aの処理__、`nil`ではない場合は__Bの処理__をするケースでよく使います。

```Swift
let name: String? = "Taro"

if let unwrappedName = name {
    //「name」が「nil」ではない場合の処理
    print(unwrappedName)
} else {
    //「name」が「nil」である場合の処理
    print("名前がありません") 
}

// -> 出力結果 Taro
```

#### `guard let`
* これ以上処理を進めたくない場合に使用します。
* `nil`が入っていたらエラーとして扱うケースだった場合などによく使います。

```Swift
let name: String? = "Taro"

guard let unwrappedName = name else { return }
//「name」が「nil」ではない場合の処理を進める
print(unwrappedName)

// -> 出力結果 Taro
```


### 3. オプショナルチェイニング
オプショナルチェイニングもオプショナル型の変数の中身が`nil`のときに安全にプログラムを実行するための機能です。
オプショナルチェイニングの使い方はオプショナル型の変数のあとに`？`をつけます。

```
オプショナル型の変数?.メソッド()
オプショナル型の変数?.プロパティ
```

`変数!`で強制的にアンラップする場合と、`変数?`でオプショナルチェイニングを使用する場合で比較してみます。

#### `変数!`で強制的にアンラップする場合
```Swift
var str1: String? = "HELLO"
let str2 = str1!.lowercased() 
print(str2) // 出力結果 hello
```
結果として`hello`が表示されます。ただし、`変数str1`が`nil`の場合にはエラーとなり、プログラムが落ちます。

#### `変数？`で強制的にアンラップする場合
```Swift
// 変数str1が「nil」でない場合
var str1: String? = "HELLO"
let str2 = str1?.lowercased() 
print(str2) // 出力結果 Optional("hello")

// 変数str1が「nil」である場合
var str1: String? = nil
let str2 = str1?.lowercased() 
print(str2) // 出力結果 nil
```
この場合、`変数str2`の値はオプショナル型になり、出力結果は`Optional("hello")`と表示されます。また、`変数str1`が`nil`の場合にもエラーとならず、結果は`nil`となります。オプショナルチェイニングの結果はオプショナル型となるため、オプショナルバインディングと組み合わせて使用されます。

#### オプショナルバインディングと組み合わせた使用
```Swift
var str1: String? = "HELLO"
if let str2 = str1?.lowercased() {
    print(str2)
} else {
    print("str1はnilです！")
}

// -> 出力結果 hello
```


# `??演算子`で`nil`であった場合のデフォルト値を設定する
```
オプショナル型の変数 ?? デフォルト値
```
`??演算子`は、左辺のオプショナル型の変数が`nil`でない場合にはその値を戻し、`nil`の場合には右辺のデフォルト値を戻します。

```Swift
var name: String?
let defaultName = "Taro"
let yourName = name ?? defaultName
print(yourName) // 出力結果 Taro
```


# まとめ
オプショナル型についてまとめてみました。私の意見にはなりますが、強制的アンラップ`！`はアプリのクラッシュの要因の一つになると思いましたので、基本的には__条件分岐が可能__な `if let`を用いてアンラップし、エラー処理の場合は__以降の処理が実行されない__`guard let`を用いてアンラップする考え方で行こうと思いました。



# 参考
* [どこよりも分かりやすいSwiftの"?"と"!"](https://qiita.com/maiki055/items/b24378a3707bd35a31a8)
* [Swiftのオプショナル型の使いこなし](https://thinkit.co.jp/article/13489)