Optional Chaining(オプショナル・チェイニング)とは、値がnilの可能性があるものへのアクセスの仕組みです。

Objective-Cでは、オブジェクト型の変数の値がnilであっても、メソッドを呼んでもランタイムエラーになりません。JavaならNullPointerExceptionになりますよね。SwiftにもObjective-Cと同様の仕組みがあり、それがOptional Chainingですが、Objective-Cのnilアクセスより洗練されています。

nilを許可する変数を宣言する

このように宣言すると初期化が必ず必要で、nilを代入することはできません。

var x: String

nilを許可する変数(プロパティ含む)は、以下のように型の後ろに?をつけます。

var x: String?

Stringかnilかもしれないよ?と捉えるとわかりやすいかもしれません。正式な呼称ではないかもしれませんが、これをOptional?型と呼ぶことにしましょう。ここではStringのOptional?型なのでString?型と呼びます。

var y = x.uppercaseString

上記のようにStringのメソッドを呼ぼうとすると
‘String?’ does not have a member named ‘uppercaseString’
というコンパイルエラーになります。String?型にuppercaseStringというメソッドはありませんよということです。

xはString型ではなく、String型をラップしたString?型(Optional?型)であることに注意が必要です。

Optional?型のメソッド呼び出し

xがString、nilどちらかの可能性がある場合は、以下のようにして?をつけてStringのメソッドを呼びます。

var y = x?.uppercaseString

String?型にラップされた値がnilなら何も実行せずnilを返しbはnilに、StringならそのuppercaseStringを呼び戻り値がbにセットされます。

xは一時的にnilのこともあるが、このコードを通る時点ではStringがセットされているべきという場合は、以下のように!をつけてStringのメソッドを呼びます。

var y = x!.uppercaseString

xは絶対にnilじゃない!というふうに捉えるとわかりやすいかもしれません。この場合は、xがnilの場合はランタイムエラーとなりクラッシュします。

このようにOptional?型からWrapされた値を?や!を指定して取り出すことをUnwrap(アンラップ)といいます。

Optional?型のメソッド呼び出しの分岐

Optional型のメソッドが値を返した時の条件分岐を以下のようにするよりは・・・

var y = x?.uppercaseString
if y != nil {
    println("x is (y).")
} else {
    println("x is nil.")
}

このようにしたほうがスマートです。ドキュメントの例もこうなっています。

if let y = x?.uppercaseString {
    println("x is (y).")
} else {
    println("x is nil.")
}

ちなみにxがnilでなくStringで、uppercaseStringがnilを返した場合も、println(“x is nil.”)へ分岐します。つまり、変数yにnil以外の値が入ったかどうかで判別されます。xがnilで呼び出しに失敗したかどうかではありません。uppercaseStringは実際にはnilを返しませんが、nilを返すメソッドの場合、注意が必要です。

Optional Chainingが成功するときのみ、メソッドを呼びたいなら以下のようにしたほうがよいでしょう。

if x != nil {
    let y = x!.uppercaseString
}

nilの状態でアクセスを許可しないOptional!型

?ではなく!で宣言するOptional型もあります。これをOptional!型と呼ぶとします。Optional!型も初期値はnilです。

var x: String!

Optional!型は、通常の変数同様?や!を付けずにプロパティやメソッドにアクセスできます。

x.uppercaseString

ただし、nilであるときはランタイムエラーとなります。プロパティやメソッドにアクセスする時は、nilでないことを保証しなければなりません。

Optional!型はJavaなど多くのメジャー言語の変数と同等と言っていいかもしれません。Javaの変数はnullのときにメソッド呼び出しを行うと、NullPointerExceptionでRuntime Errorとなるでしょう(例外をcatchしない限り)。ですから、実行時にnullである可能性があるものは、nullであるかどうかをチェックする必要があります。

Optional!型も、実行時にnilの可能性がある場合は、チェックしてからメソッドで呼び出しを行う必要があります。

if x != nil {
   var y = x.uppercaseString
}

ViewControllerのSubclassのようにinitではなくviewDidLoadでプロパティを初期化して、それ以降はnilでないことが確定しているプロパティがあると思います。こういうものは、Optional!型で定義すると良いでしょう。viewDidLoad以降実行されるコードで、いちいちプロパティに!をつける手間がなくなりますから。

実際にXcodeが自動生成するコードでは、IBOutlet変数は以下のようにOptional!型で作られています。

@IBOutlet weak var detailDescriptionLabel: UILabel!

ViewControllerのプロパティをOptional型で宣言する件については、以下の記事にもまとめたので、ご参考までに。

ViewControllerのプロパティをOptional型で宣言する