nilとOptional型
何もないことを意味する値nilとOptional型
nil(ニル)とは、「何もない」ことを表す特別な値です。ただし、空白文字や数値の0とは別物です。変数の初期値としてよく利用されます。
・nilは空白文字や0とは異なる
「なにもない」ものをコンピュータが扱うことはできません。計算しろ、表示しろ、と言われてもコンピュータは困ります。そのため、Swiftでは普通の定数や変数にnilを入れることはできません。
(つまり、いつも使っている普通の型では、必ず値を入れなければいけません。そのため、宣言後は必ず代入を行わないとエラー表示がでます。)
Swiftでnillを扱うには、Optional(オプショナル)型という特殊な型を使って定数・変数を宣言します。
Optional型
1 2 |
var value1: Optional<Int> var value2: String? // OptionalのString型変数の宣言 |
いつも使っている型を、Optional<型> か 型?と記載することで、その定数/変数にnilを入れることができるようになります。(書く手間の少ない「型?」の書き方が一般的です。)
これを「Optional型でラップする」といいます。
ラッピングをすることで、存在する値も、存在しない値も、実体をもたせて扱うことができる、といったイメージです。中身がわからなくなるため、型(データの種類)に「?」をくっつける、と覚えてください。
Optional型の扱い方
いざOptional型から値を取り出そう、という時は
①ラップを外してあげる(アンラップ)
②もし中身がnil(なにもない)だったら処理を回避させる の2つが必要になります。
①アンラップ 〜末尾に!をつける〜
1 2 3 |
var str: String? = "コンピュータ" print(str) //ラップされたままの状態 print(str!) //アンラップされた状態 |
上記をPlaygroundで出力結果を試してみてください。ラップされたままだと警告が出ます。
②処理の回避 〜代表的な方法3つ〜
もしラップされた箱から、「何も無い」という値が出てきてそれを出力しろ、計算しろ、と言われるとコンピュータはパニックになり、最悪アプリがエラーで動かなくなります。
安全に動かすためにも、「nilが出てきたら代わりにこれを行ってね、もしくは何もしなくていいよ」という指示を与えます。
1、if構文の条件文で回避
1 2 3 4 |
var str: String? = "コンピュータ" if str != nil { print(str!) //strがnilでなければこの処理を行います。また、出力するのでアンラップしています。 } |
if構文は後ほど詳しく解説いたします。
if に続く str != nil は「strがnilではない場合に、{}内の処理をする、それ以外はこの処理を通らない」という意味の条件文です。
strに中身が入っている場合のみ出力して、というお願いをしています。
2、代入が成功した場合は処理、失敗した場合は回避(if let文)
1 2 3 4 |
var str: String? = "コンピュータ" if let str = str { print(str) //let str = 代入したい値 が成功したらここの処理を行います } |
if に続く let str = str は代入を行っており、「この代入が成功したら{}の処理を行う、失敗したらこの処理は通らない」という意味の文章です。if let文と呼ばれます。
あえて同じstrが2回出てきていますが、これはわかりやすく書き直すと以下のようになります。
var str: String? = "コンピュータ"
if let newStr = str {
print(newStr)
}
つまり、if文の中で新しく宣言した定数(Optional型ではない普通の定数)に、値を移し替えていた、ということです。
if let文で、同じ名前の定数に移し替えた場合には、{ }内の処理ではアンラップ後の定数が優先的に参照されます。そのため同じ変数/定数名を使うことで、新しい変数/定数名を使う手間を省く、という書き方が多くされます。
最初のうちはわかりやすく、別の名前をつけた定数に移し替えても問題ありません。
まとめると、if let文では、代入しようとしたものがnilだったら代入失敗となり、処理が回避されます。
値があった場合は、Optional型でない普通の定数に移し替えて、それを使う、といった方法です。
アンラップ処理後の変数を利用しない場合は、「_(アンダーバー)」で省略することができます。
var str: String? = "コンピュータ"
if let _ = str {
print("変数はnilではありませんでした")
}
3、nilだった場合は別に用意した値を使って回避
1 2 |
var str: String? = "コンピュータ" print(str ?? "中身は何もなかった") //strがnilの時、"中身は何もなかった"が表示される |
これは、nil対策のために用意された特別な書き方で、
変数がnilでなかったらstrを使用、変数がnilだったら??以降に与えられた値を使用します。
また、定数/変数の宣言時に
let a = b ?? ""
という形で使うこともできます。(bはユーザーが入力した値など、nilの可能性がある値、と考えてみてください)bがnilだったら、""空白文字をaに代入します。もちろん文字列""以外に数字の0なども代わりに扱うことができます。
アンラップの手間を省く暗黙的アンラップ型
値を扱う時にアンラップを省略できるOptional型があります。
これを暗黙的アンラップ型(Implicitly Unwrapped Optional)と言います。
1 2 |
var value: String! = "コンピュータ" // 暗黙的アンラップ型String変数の宣言 print(value) // 出力を試してみましょう |
Optional型を宣言するときに、?を!にしておくことで、扱う時に自動でアンラップしてくれます。
しかし以前にも説明した通り、何もない値を出力したり計算したりすることはできません。
つまり中身がnilだった場合に出力を命令してしまうと、エラーが発生します。
そのため、値を扱う際に絶対にnilになる可能性がない変数・定数に使います。
それならばOptional型ではない普通の型を使えば良いのでは?とお考えになるでしょう。しかし、実は下記のような場合には必要なのです。
1 |
@IBOutlet weak var myLabel: UILabel! |
もし、すでにXcodeで「部品をコードと紐づける」という操作を履修した方であればこのようなコードを見たことがあるでしょう。部品をコード化する際、自動で型が暗黙的アンラップ型になっていますね。
なぜnilが入れるようになっているかというと、Xcodeの仕様上、部品を画面に表示するまでの過程でnil(値が確定できない状態の時がある)が入る必要があるからです。
※テキストフィールドやラベルに何も入力されなかった場合は自動的にnilではなく空文字が入るようになっています。普通に使う分には、アンラップなどの手間を考えずに使うことができます。
意識することは少ないでしょうが、型の後ろの!にはこのような意味があることを覚えておいてください。