Swift さくっと確認したい基礎文法 [Optional(オプショナル) その２]


前回に引き続き、Optional(オプショナル)の続きになります。
今回は「オプショナルバインディング」と「オプショナルチェインニング」についてです。


## オプショナルバインディング

オプショナルバリューがnilでなければ、アンラップして変数に代入する。
nilであればfalseを返す機能のことです。

これはif文とwhile文の分岐で利用できます。

```swift
if let 変数 = オプショナルバリュー {
    // 処理
}

while (let 変数 = オプショナルバリュー) {
    // 処理
}
```

わざわざnilチェックを単独で書く必要がないため、かなり便利です。

```swift
var staff:String?
if let s = staff { // staffがnilなのでfalse
    println("本日の担当者は\(s)です。")
} else {
    println("本日は担当者なし")
}
```

```lang:出力
本日の担当者はなし
```

### おまけ
また、以前は複数条件の場合に下記のように書く必要があり、
`nil`チェックが冗長になっていました。

```lang:swift
if staff != nil && guest != nil {
    
} else {

}
```

swift1.2からは
下記のようにすっきりと書くことができるようになりました。

```swift
if let s = staff, g = guest {
    
} else {
    
}
```

## オプショナルチェインニング

オブジェクトのプロパティ、メソッド等にアクセスする際に、
それがnilだった場合にエラーが起きてしまいます。

それを防ぐためにプロパティ名やメソッド名に`?`をつける記述方法のことを
**オプショナルチェインニング**といいます。


今回はSoldierクラスとWeaponクラスというクラスを使って説明します。

```swift

class Soldier {
    var weapon:Weapon? // オプショナル
}

class Weapon {
    var name:String = "Excalibur"
}
```

Soldierクラスのインスタンスを作成して
Weapon.nameにアクセスしてみます。

```swift
var soldier = Soldier() // soldier.weapon = nil
println(soldier.weapon!.name) // weaponがnilなのでnameにアクセスした段階でエラー。
```

Soldierクラスのweaponプロパティはオプショナルバリューなので、
初期値のnilが入っています。
nilであるweaponのnameプロパティにアクセスしたためエラーが起きます。


```swift
var soldier = Soldier() // soldier.weapon = nil
println(soldier.weapon?.name) // nil
```

`weapon?`にしたことで
weaponがnilであることを確認した時点で処理が終わり、
エラーになることなく`nil`を返してくれます。


## メソッドの戻りがオプショナルバリューの場合

次に、メソッドの戻り値がオプショナルバリューの場合を見てみます。

use()はItemを返します。
そのItemのnameプロパティにアクセスするケースで考えてみます。

下の`use()!.name as String!`のようにすると、
use()の戻り値がnilの場合、下記のようにエラーが発生します。



```swift

    // ５回ループ
	for _ in 0...5 {
        println("手持ちの道具：\(use()!.name as String!)")
    }

    struct Item {
        var name:String
    }
    
    var item:Item = Item(name: "たいまつ")
    var useCount:Int = 3 // 使用回数
    
    func use() -> Item? {
        
        if(useCount == 0){
            print("\(self.item.name)を持っていない。")
            return nil
        } else {
            useCount--
            print("\(self.item.name)を使った。周辺が明るくなった。")
            
            if(useCount == 0) {
                print("\(self.item.name)が燃え尽きた。")
            }
            return self.item
        }
    }
```

```lang:出力
たいまつを使った。周辺が明るくなった。手持ちの道具：たいまつ
たいまつを使った。周辺が明るくなった。手持ちの道具：たいまつ
たいまつを使った。周辺が明るくなった。たいまつが燃え尽きた。手持ちの道具：たいまつ
たいまつを持っていない。fatal error: unexpectedly found nil while unwrapping an Optional value
```

そこでプロパティと同じように
`use()`の後ろに`?`をつけます。

ここでは`use()?.name as String!`のようにすると、
エラーにならず、`use()?.name`は`nil`が返ってきます。


```swift

    // ５回ループ
	for _ in 0...5 {
        println("手持ちの道具：\(use()?.name as String!)")
    }

    struct Item {
        var name:String
    }
    
    var item:Item = Item(name: "たいまつ")
    var useCount:Int = 3 // 使用回数
    
    func use() -> Item? {
        
        if(useCount == 0){
            print("\(self.item.name)を持っていない。")
            return nil
        } else {
            useCount--
            print("\(self.item.name)を使った。周辺が明るくなった。")
            
            if(useCount == 0) {
                print("\(self.item.name)が燃え尽きた。")
            }
            return self.item
        }
    }
```

```lang:出力
たいまつを使った。周辺が明るくなった。手持ちの道具：たいまつ
たいまつを使った。周辺が明るくなった。手持ちの道具：たいまつ
たいまつを使った。周辺が明るくなった。たいまつが燃え尽きた。手持ちの道具：たいまつ
たいまつを持っていない。手持ちの道具：nil
たいまつを持っていない。手持ちの道具：nil
たいまつを持っていない。手持ちの道具：nil
```


「オプショナルバインディング」、「オプショナルチェインニング」をうまく使うことで
nilのエラーで落ちる、ということがかなり減ると思います！

Swiftではオプショナルをしっかり理解して実装していくことが
かなり重要だと思うので、しっかり身につけたいところです。。。