オプショナルが nil でない場合にプロパティやメソッド、サブスクリプトを呼び出したいオプショナル値の後にクエスチョンマーク (?) を置いて、オプショナルチェーンを指定します。オプショナル値のアンラップを強制するためにオプショナル値の後にエクスクラメーションマーク (!) を置くことによく似ています。一番の違いは、オプショナルチェーンはオプショナルが nil のときうまく失敗しますが、強制アンラップはオプショナルが nil のとき実行時エラーを起こすことです。

オプショナルチェーンを nil の値に対して呼び出せることを反映して、問い合わせたプロパティやメソッド、サブスクリプトがオプショナルでない値を返す場合でも、オプショナルチェーン呼び出しの結果は常にオプショナル値となります。オプショナルチェーン呼び出しが成功した(返されたオプショナルに値がある)か、チェーンに nil 値があったために成功しなかった(返されたオプショナル値が nil)かを確認するために、この返されたオプショナル値を使用することができます。

具体的には、オプショナルチェーン呼び出しの結果は、期待される戻り値と同じ型になりますが、オプショナルにラップされています。通常 Int を返すプロパティは、オプショナルチェーンでアクセスされるときには Int? を返します。

次からのいくつかのコードスニペットでは、オプショナルチェーンがどのように強制アンラップと異なるかや、どのようにして成功を確認するかを示しています。

初めに、2 つのクラス Person と Residence が定義されています。

class Person {
    var residence: Residence?
}

class Residence {
    var numberOfRooms = 1
}

Residence のインスタンスには、デフォルト値 1 の Int プロパティ numberOfRooms があります。Person のインスタンスには、Residence? 型のオプショナル residence プロパティがあります。

新しい Person インスタンスを生成した場合、residence プロパティはオプショナルであるためデフォルトの nil に初期化されます。次のコードでは、john には nil 値の residence プロパティがあります。

let john = Person()

値のアンラップを強制するために residence の後にエクスクラメーションマークを置いて、この人の residence の numberOfRooms プロパティにアクセスしようとすると、存在しない residence 値をアンラップすることになり、実行時エラーを起こします。

let roomCount = john.residence!.numberOfRooms
// 実行時エラーを起こす

このコードは john.residence に nil でない値があるときには成功し、適切な部屋数を含む Int 値を roomCount に設定にします。ですが、上述したように、このコードは residence が nil のときには常に実行時エラーを起こします。

オプショナルチェーンは numberOfRooms の値にアクセスするためのより効果的で害の少ない方法です。オプショナルチェーンを利用するには、エクスクラメーションマークの代わりにクエスチョンマークを使用します。

if let roomCount = john.residence?.numberOfRooms {
    print("John's residence has \(roomCount) room(s).")
} else {
    print("Unable to retrieve the number of rooms.")
}
// "Unable to retrieve the number of rooms." と出力

このようにして Swift にオプショナル residence プロパティを「チェーン」させて、residence が存在する場合には numberOfRooms の値を取り出します。

numberOfRooms にアクセスする試みは失敗する可能性があるため、オプショナルチェーンは Int? 型、つまりオプショナル Int 型の値を返します。上の例で見たように、residence が nil のときには、numberOfRooms にアクセスできないことを反映して、このオプショナル Int もまた nil となります。このオプショナル Int はオプショナルバインディングでアクセスされていて、オプショナルでない値を整数にアンラップして roomCount 変数に代入します。

numberOfRooms がオプショナルでない Int の場合にでもそうなることに注目してください。オプショナルチェーンで問い合わせされることにより、numberOfRooms の呼び出しは常に Intではなく Int? を返します。

john.residence に Residence インスタンスを代入することで、nil 値ではなくなります。

john.residence = Residence()

この時点で、john.residence は nil ではなく、Residence インスタンスを含んでいます。前と同じようにしてオプショナルチェーンで numberOfRooms にアクセスすると、numberOfRooms のデフォルト値 1 を含む Int? を返します。

if let roomCount = john.residence?.numberOfRooms {
    print("John's residence has \(roomCount) room(s).")
} else {
    print("Unable to retrieve the number of rooms.")
}
// "John's residence has 1 room(s)." と出力

Portions of this page are translations based on work created and shared by Apple and used according to terms described in the Creative Commons Attribution 4.0 International License.