LoginSignup
17

More than 5 years have passed since last update.

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

Last updated at Posted at 2015-04-12

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

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

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

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

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

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

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

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

おまけ

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

swift
if staff != nil && guest != nil {

} else {

}

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

if let s = staff, g = guest {

} else {

}

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

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

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

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


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

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

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

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

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

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の場合、下記のようにエラーが発生します。


    // 5回ループ
    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
        }
    }
出力
たいまつを使った。周辺が明るくなった。手持ちの道具:たいまつ
たいまつを使った。周辺が明るくなった。手持ちの道具:たいまつ
たいまつを使った。周辺が明るくなった。たいまつが燃え尽きた。手持ちの道具:たいまつ
たいまつを持っていない。fatal error: unexpectedly found nil while unwrapping an Optional value

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

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


    // 5回ループ
    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
        }
    }
出力
たいまつを使った。周辺が明るくなった。手持ちの道具:たいまつ
たいまつを使った。周辺が明るくなった。手持ちの道具:たいまつ
たいまつを使った。周辺が明るくなった。たいまつが燃え尽きた。手持ちの道具:たいまつ
たいまつを持っていない。手持ちの道具:nil
たいまつを持っていない。手持ちの道具:nil
たいまつを持っていない。手持ちの道具:nil

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

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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17