Optional型とは
nilを代入できる型のこと。
let a: Int? = Int("42") // Optionalで宣言
let b: Optional<Int> = Int("42") // 上と同義
ただし他の型の変数に代入したりする場合、unwrapという処理が必要になる。
その際、nilが代入されている可能性があるので慎重に扱わなければなりません。
ここではOptional型を安全にunwrapして扱うための5つの方法をまとめました。
1. Force Unwrapping
変数の中身がなんであれとにかくunwrapする。
もしnilだった場合はruntime errorとなってしまうため、nilでないことが確かな場合に使うと良い。
"Unconditional Unwrapping"とも言うらしい。
let myOptioal: String? // Optional<String>で宣言
myOptional = "Angela" // 文字列を代入
print(myOptional!) // "Angela"が出力される
let myOptioal: String? // Optional<String>で宣言
myOptional = nil // nilを代入
print(myOptional!) // runtime errorとなる
2. Check for nil value
if statementでunwrapしようとしている変数の中身がnilかどうか判定し、trueの場合の処理でunwrapをする。
let myOptioal: String? // Optional<String>で宣言
myOptional = nil // nilを代入
if myOptional != nil {
print(myOptional!) // nilでない場合のみunwrapするので安全
} else {
print("myOptional was found to be nil") // nilだった場合はこちらの処理が実行される
}
unwrapする前にnilかどうか判定するので安全な一方で、毎回unwrapしなくてはならないので面倒。そんなときは次の"Optional Binding"が有効。
let myOptioal: String? // Optional<String>で宣言
myOptional = nil // nilを代入
if myOptional != nil {
let text1: String = myOptional!
let text2: String = myOptional!
let text3: String = myOptional! // 毎回unwrapする必要がある
} else {
print("myOptional was found to be nil")
}
3. Optional Binding
if statementで新たな定数にOptional型の変数を代入する。nilでない場合はif let safeOptional = myOptional
の判定はtrueになり、nilの場合は判定の結果がfalseになる。ブロックの中では非OptionalのString型であるsafeOptional
が使えるのでunwrapは不要となるので便利。
let myOptioal: String? // Optional<String>で宣言
myOptional = nil // nilを代入
if let safeOptional = myOptional {
// myOptionalがnilでない場合はtrueになりここの処理が実行される
let text1: String = safeOptional
let text2: String = safeOptional
let text3: String = safeOptional //条件の箇所で宣言したsafeOptionalは非OptionalのStringなのでunwrapは不要
} else {
// myOptionalがnilの場合はfalseになりここの処理が実行される
print("myOptional was found to be nil")
}
4. Nil Coalescing Operator
Optional型の変数の中身がnilの場合にデフォルト値を与えたい場合に有効です。
COALESCE
といえばSQLの関数にもありますね。"NULL以外の最初の引数を返す"というものです。
SwiftのNil Coalescing Operator
という演算子も同様の考え方が使えます。
optional ?? defaultValue // optionalがnilでない場合はoptinalを、nilの場合はdefaultValueを返す
let myOptioal: String? // Optional<String>で宣言
myOptional = "Angela" // 文字列を代入
let text: String = myOptional ?? "I am the default value"
print(text) // "Angela"が出力される
let myOptioal: String? // Optional<String>で宣言
myOptional = nil // nilを代入
let text: String = myOptional ?? "I am the default value"
print(text) // "I am the default value"が出力される
5. Optional Chaining
これまではOptional型のStringなどを見てきましたがstructのインスタンスの場合はどうでしょうか。Optional型のユーザー定義のstructを格納する変数や定数が宣言されている場合にも安全にunwrapしたいです。これにはまた別の方法が用意されています。
struct MyOptional {
var property = 123
func method() {
print("I am the struct's method.")
}
}
let myOptional: MyOptional? // Optional<MyOptional>で宣言
myOptional = MyOptional() // MyOptionalのインスタンスを代入
print(myOptional?.property) // 123が出力される
myOptional?.method() // "I am the struct's method."が出力される
struct MyOptional {
var property = 123
func method() {
print("I am the struct's method.")
}
}
let myOptional: MyOptional? // Optional<MyOptional>で宣言
myOptional = nil // nilを代入
print(myOptional?.property) // myOptionalはnilなのでpropertyにはアクセスしない
myOptional?.method() // myOptionalはnilなのでmethodは実行しない
まとめ
Optional型はSwiftの便利な点であると同時に混乱することが多い箇所だと思うので、これらを状況によって使い分けることが大事ですね。
参考
https://developer.apple.com/documentation/swift/optional
https://www.udemy.com/course/ios-13-app-development-bootcamp/