強制アンラッピングとオプショナル・チェイン
クラスや構造体の定義で、ストアド・プロパティに nil を許可するオプショナル値を利用すると、プロパティが nil になる場合があります。
こうした場合、[オブジェクト].[プロパティ].[プロパティ].... とプロパティをたどっていくときに、途中で nil を参照してしまう可能性が出てきてしまうわけです。
nil のプロパティを参照を試みると通常は実行時エラーとなります。
このため、他のプログラミング言語では、どれが nil (null) であるかチェックしながら、プロパティを参照していました。
あるいは例外がスローされるのに期待しつつ大胆に参照してしまうとか・・・。
Swift ではこのような状況を避け、もっと礼儀正しく、オプショナル値のプロパティを参照する方法が導入されています。
強制アンラッピング
まずはオプショナル値がプロパティになるときの問題点を見てみましょう。
struct Address {
var city : String
}
struct Person {
var name : String?
var address : Address?
}
var p = Person()
p.name = "Hanako"
if p.address != nil && p.address!.city == "Sapporo" {
print( "Sapporo!" )
}
else {
print( "Somewhere else!" )
}
実行結果
Somewhere else!
この例では、住所 (Address) 型と人 (Person) 型が定義されていますが、Person のプロパティ name と address はいずれも、String?、Address? という風にクエスチョンマークが付けられています。
つまり、オプショナル値として定義されています。これらは nil になる可能性があります。
このため、Person のインスタンスを作ったあと、Address 型である address プロパティの city プロパティを参照したいなら、 まずは address が nil ではないことを確認して、city を参照できることを確認してから参照しています。
このように、オプショナル値は == nil とか != nil として値があることをチェックしてから使います。nil でないことがわかったら、 「値があることがわかっているから、! を付けてそれを使う」と宣言してその値を使うことができます。
これをオプショナル値の強制アンラッピング (forced unwrapping) といいます。
nil チェックをしないで、強制アンラッピングすると次のように、実行時エラーが発生する可能性が出てきます。
struct Address {
var city : String
}
struct Person {
var name : String?
var address : Address?
}
var p = Person()
p.name = "Hanako"
if p.address!.city == "Sapporo" {
print( "Sapporo!" )
}
else {
print( "Somewhere else!" )
}
実行結果
Fatal error: Unexpectedly found nil while unwrapping an Optional value Current stack trace: 0 libswiftCore.so 0x00007f4d01701810 _swift_stdlib_reportFatalError + 171 ... Illegal instruction
Swift ではこのような状況をより簡便に記述する方法があります。
オプショナル・チェインとは
上記の状況をより簡便に行なうために、Swift ではオプショナル・チェイン (optional chaining) という仕組みがあります。
オプショナル値のプロパティを参照する際に ? を付けて参照します。するとそのオプショナル値が nil である場合、実行時エラーを発生させるのではなく、そのプロパティの値を nil として返します。
struct Address {
var city : String
}
struct Person {
var name : String?
var address : Address?
}
var p = Person()
p.name = "Hanako"
if p.address?.city == "Sapporo" {
print( "Sapporo!" )
}
else {
print( "Somewhere else!" )
}
Somewhere else!
オプショナルチェインを使うと、上述の例はこのように簡単に記述できるようになります。