読者です 読者をやめる 読者になる 読者になる

Codable Tech Blog

CodableがiOSプログラミング、クライアントサイド(JavaScript)・サーバーサイド(Java,C#,PHP)プログラミング、その他技術(MySQL、Linuxなど)について発信しています

MENU

Swift nil オプショナル(Optional)

値とnil

通常、オブジェクトは何らかの値を持ちますが、値をもたないケースも存在します。例えば、名前を管理するプログラムを作成する時、ファーストネーム、ミドルネーム、ラストネームの3つで名前を管理したとします。日本人の多くはミドルネームを持ちませんので、ミドルネームは値をもちません。Swiftではnilという値が存在し、これはある型に所属する変数が値をもっていないことを示します。次の例はファーストネームとラストネームに文字列オブジェクトを割り当て、ミドルネームにnilを割り当てた例です。

この場合、middleName = nilの行でコンパイルエラーが発生します。実はオブジェクトが存在しないことを示すnilは通常の型では扱えないのです。しかし、オブジェクトが値を持たないならば、値をもたないことを示すnilをオブジェクトに設定する必要があります。Swiftでは、ある型の変数が値をもっているのか、値をもっていないのか示すオプショナル型が用意されています。

オプショナル(Optional)型

オプショナル型とは変数が値をもつのか、もしくは値をもたないのかを表現する型です。オプショナル型であることは以下のように示します。

型名?

型名の部分には変数が値をもつ場合に保持する型を指定します。例えば、String型の値をもつか、もしくは値をもたないオプショナル型を宣言する場合、次のようになります。

var middleName:Strig?

変数strはString型の値をもつか、もしくは値をもたないオプショナル型の変数です。オプショナル型の変数であれば、次のようにString型の値(文字列オブジェクト)を代入することもできますし、nilを代入することもできます。ただし、String型の値が入っているとはいえ、型はオプショナル型ですのでString型のメッセージは送れないことに注意してください。

もし、このオプショナル型をString型として扱いたい場合、次の強制アンラッピング(Forced Unwrapping)かオプショナルチェイン(Optional Chaining)を利用する必要があります。

強制アンラッピング(Forced Unwrapping)

強制アンラッピングおよびオプショナルチェインはどちらもオプショナル型を保持している値の型として扱うものです。例えば、オプショナル型がString型の値を保持していた場合、String型として扱えるようにするということです。強制アンラッピングは次のように記述します。

オプショナル型の変数!

例えば、String型の値をもつオプショナル型の変数に対して強制アンラッピングを行うには次のようにします。

middleName!とすることでオプショナル型の変数ではなく、String型の変数としてmiddleNameを扱うことができます。
ただし、もし、middleNameにnilが代入されていた場合、プログラムが強制終了します。このため、強制アンラッピングはオプショナル型の変数に値が確実に設定されていることが保証されている時以外は利用すべきではありません。

オプショナルチェイン(Optional Chaining)

オプショナルチェインも強制アンラッピング同様、オプショナル型を保持している値の型として扱うものです。違いは変数にnilが代入されていた時の振る舞いです。オプショナルチェインの場合、変数の値がnilだった場合、強制終了はしません。処理が無視されるだけです。オプショナルチェインは次のように記述します。

オプショナル型の変数?

強制アンラッピングの例をオプショナルチェインを用いた形に書き換えたのが以下です。

変更したのは変数名のあとの!の部分を?に変えたことだけです。この場合だと、middleNameの値がnilであってもプログラムが強制終了せず、そのまま処理が継続されます。なお、nilに対してメッセージを送っても何も処理は行われません。

オプショナルバインディング(Optional Binding)

Optional型の変数を利用する場合、nilが含まれている可能性があることから、変数の値がnilかどうかをチェックして、値がある場合とnilの場合で処理の切り分けを行うことがよくあります。Optional型の変数がnilかどうかをチェックするには次のようなif文を利用します。

if 変数名 != nil {
    //Optional型の変数が値をもっていた場合の処理
}else{
    //Optional型の変数がnilだった場合の処理
}

例えば、変数middleNameがnilかどうかで処理を切り分けるif文は次のようになります。

ここで2行目のprintlnでmiddleNameの値を出力している箇所に注目してください。middleNameはOptional型ですのでString型の変数として利用するには強制アンラッピングかオプショナルチェインを行う必要があるのでした。2行目の処理が行われるときは、1行目のif文でnilでないことが保証されているので強制アンラッピングを行い、String型の変数として扱っています。
Optional型の値がnilかどうかをチェックするのに上記のようなif文を利用してもよいのですが、Swiftではオプショナルバインディング(Optional Binding)という便利な構文が用意されています。OptionalBindingはOptional型の変数がnilかどうかをチェックし、nilでなければ一時的変数や一時定数に値を代入する構文です。
OptionalBindingの構文は次のようになります。

if let 定数名 = Optional型変数 {
    文
}
もしくは
if var 変数名 = Optional型変数 {
    文
}

オプショナルバインディング構文ではOptional型の変数が値を持っていた時、ifブロックの中の処理が行われます。また、Optional型の変数が値をもっていた場合、if文の左辺の定数もしくは定数にその値が代入されます。しかも、代入された値はアンラップされた型の値で代入されていますので、ifブロックの中で!や?を末尾につけることなく、変数に代入されている値を利用することができます。先ほどのmiddleNameの例をオプショナルバインディングを用いて書き直すと以下のようになります。

nilチェックとアンラッピングを同時に行ってくれる便利な構文ですのでどんどん使っていくとよいでしょう。