1. はじめに
この記事はレコチョク Advent Calendar 2021の21日目の記事となります。
株式会社レコチョクで、iOSアプリの開発をしている新卒1年目の後藤です。
米津玄師・スキマスイッチ・BUMP OF CHICKENのみなさんに、日々活力を頂いております。
Swiftにはオプショナル型というnil
を許容した型があります。これを非オプショナル型の値として取り出すためには、アンラップという作業が必要です。
この記事では
- !(強制アンラップ)
- if let
- guard let
- ??(Nil coalescing operator)
を使ってどのようにアンラップするか、どう使い分けるかを中心にまとめます。
2. オプショナル型とは
Swiftでは通常のデータ型(Int型やString型など)には、nil
を代入することができません。
そこで、オプショナル型を使うと変数にnil
を代入することができるようになります。
var hoge: String? // オプショナル型の宣言
var fuga: String // 非オプショナル型の宣言
hoge = nil // ok(オプショナル型なので、nilが代入できる)
fuga = nil // コンパイルエラー(非オプショナル型なので、nilが代入できない)
3. !での強制アンラップ
オプショナル型の変数の値を、非オプショナル型の値として取り出す(上記の例でいうとhoge
のString?
型をString
型にする)ためには、アンラップという作業が必要です。
変数名!
と書くと、強制的にアンラップすることができます。しかし、アンラップした変数がnil
であった場合、実行時エラーが発生してしまいます。
var hoge: String? // オプショナル型の宣言
print(hoge!) // 実行時エラー(hogeがnilのため強制アンラップに失敗し、実行時にエラーが発生)
そのため、オプショナル型の変数がnil
でないことが保証できる場合のみ使用しましょう。
4. オプショナルバインディング(if let・guard let)でのアンラップ
上記の例のように変数名!
でアンラップすると、nil
であった場合、実行時エラーが発生してしまいます。
そこで、安全にアンラップする方法の一つとして、オプショナルバインディングがあります。オプショナルバインディングを使うことで、nil
であるかを確認して処理を進めることができます。
オプショナルバインディングは、2つの構文が存在します。
- if let
- guard let
if let
if let文は、オプショナル型変数にnil
が含まれているかどうかによって、後続の処理を分岐させることができます。
let hoge: String? = nil // hogeの中身はnil
if let _hoge = hoge {
// hogeがnilではなかった時の後続処理…
} else {
// hogeがnilだった時の後続処理…
}
guard let
guard let文は、オプショナル型変数にnil
が含まれている場合、その時点で処理を中断させることができます。
下記のコードではhoge
がnil
のため、else節でreturn
され、早期リターンします。また、if let文と比べて、後続の処理(コード)のネストを浅くすることができ、コードが読みやすくなります。
なお、guard let文は、関数の中でしか実行することができないため注意が必要です。
let hoge: String? = nil // hogeの中身はnil
guard let _hoge = hoge else { return } // hogeはnilなのでreturnされる
// hogeがnilではなかった時の後続処理…
// if letと比べて後続処理がネストの中に入らないため、ネストを浅くすることができる
両方に共通すること
if let文も guard let文も、条件をnil
以外にも指定することができます。例えば下記の例だと、hoge
がnil
ではないかつ、A
という値を持っていたらprint文が実行されます。
let hoge: String? = "A"
if let _hoge = hoge, _hoge == "A" {
print("hogeはnilではない かつ Aという文字列が入っています")
}
また、複数の変数を同時に、nil
が入っているのかを確認することもできます。
var a: Int? = 10 // オプショナル型(nilを許容する)
var b: Int? = 20 // オプショナル型(nilを許容する)
if let a = a, let b = b {
// aとbが両方ともnilではなかった時の後続処理…
print(a + b) // 30
} else {
// aとbのどちらか一方でもnilだった時の後続処理…
print("failed")
}
func add(_ a: Int?, _ b: Int?) {
guard
let a = a,
let b = b
else {
return // returnを忘れるとコンパイルエラー
}
// a,bともにnilではなかった時の後続処理…
// if letと比べて後続処理がネストの中に入らないため、ネストを浅くすることができる
print(a + b)
}
var a: Int? = 10 // オプショナル型(nilを許容する)
var b: Int? = 20 // オプショナル型(nilを許容する)
add(a, b) // 30
5. ??(Nil coalescing operator)でのアンラップ
Nil coalescing operatorでも、オプショナル型の変数がnil
なのかを確かめることができます。
変数 = オプショナル型変数 ?? (nilの場合の値)
Nil coalescing operatorはnil
だった場合、予め用意しておいた値を代入します。そのため、先ほど紹介したif let文やguard let文とは異なりnil
だったときの処理を条件分岐させて書くことができません。
Nil coalescing operatorは、nil
だったときのデフォルト値が想定されている場合で使用すると良いです。例えば下記の例では、楽曲アプリを作成していてタイトルやアーティストの情報が取得できなかったら、予め用意しておいたデフォルト値を入れています。
var title: String?
var artist: String?
titleLabel.text = title ?? "不明なタイトル"
artistLabel.text = artist ?? "不明なアーティスト"
6. まとめ
本記事では、オプショナル型の変数に格納された値を取り出す(アンラップする)ための方法として、4通りの方法を紹介しました。
- !(強制アンラップ)
-
nil
の場合で、実行時エラーが発生してしまう -
nil
でないことが保証できる場合のみ使用する
-
- if let
-
nil
の場合で、行いたい処理がある場合に使用する
-
- guard let
-
nil
の場合で、それ以上処理を進めたくない場合に使用する(早期リターンできる) - 関数の中でしか使うことができない
-
- ?? (Nil coalescing operator)
-
nil
の場合で、デフォルト値を設定できる場合に使用する -
nil
の場合で、条件分岐をさせることができない
-
最後まで読んでいただき、ありがとうございました。
明日のレコチョク Advent Calendar 2021は22日目「MediaElement.jsでメディアプレイヤーのUIをサクッとつくる」となります!お楽しみに。
参考記事
【初心者向け】Swiftの"?"と"!",はじめからていねいに (1/2)
【初心者向け】Swiftの"?"と"!",はじめからていねいに (2/2)
【Swift】guard文、guard let文の使い方/ if letとの違いも
Swiftでif let文を使って出来ることとguard letの使い分けに関して
新卒iOSエンジニアがコードレビューを受けて気づいたポイント4選
この記事はレコチョクのエンジニアブログの記事を転載したものとなります。