【Swift】コードをコンパクトに記述できるオプショナルチェーン(optional chaining)の性質と活用例
記事内に広告を含む場合があります。記事内で紹介する商品を購入することで、当サイトに売り上げの一部が還元されることがあります。
最近はSwiftでコーディングすることが多い@akio0911です。今日はSwiftでコードをコンパクトに記述できる「オプショナルチェーン」という仕組みについて紹介します!
オプショナルチェーンの基本
オプショナル型なプロパティを持つ、以下の様なクラス群が定義されていたとします。
class A { var b:B? } class B { var c:C? } class C { var name:String = "" var age:Int = 0 func isMale() -> Bool { return true } func display() { print("name = \(name), age = \(age)") } }
そして、以下のようにオブジェクトを生成したとします。
var objectC = C() objectC.name = "sato" objectC.age = 35 var objectB = B() objectB.c = objectC var objectA:A? = A() objectA!.b = objectB
ここでobjectCのnameプロパティにアクセスしたいとします。こんな時に活用できるのが「オプショナルチェーン (optional chaining, optional chain) 」です。
let n = objectA?.b?.c?.name
上記のコードは以下の様な動きをします。
- objectA, b, c の全てがnilでは無い場合、定数nにはnameが代入される
- objectA, b, c のいずれかがnilの場合、定数nはnilとなる
この時、定数nはnilになりえるので、その型はnameと同じString型ではなく、String?型(オプショナル)となります。
オプショナル束縛と組み合わせる
オプショナルチェーンは、以下のようにオプショナル束縛 (optional binding) と組み合わせて使うことができます。
if let name = objectA?.b?.c?.name { // objectA, b, c の全てがnilでは無い場合、ここが実行される println(name) }
辞書へのアクセスにオプショナルチェーンを使ってみる
SwiftのDictionaryは、キーを指定してアクセスする際にオプショナル型が返ってくるので、以下のように記述することができます。
var dictionary = [String:C]() dictionary["sato"] = objectC if let name = dictionary["sato"]?.name { // dictionary["sato"] が存在する場合、ここが実行される println(name) }
オプショナルチェーンでメソッドを呼び出す
オプショナルチェーンではメソッドも呼び出すことができますが、その場合はメソッドの返り値のオプショナル型が返ってきます。
例えば先程のCクラスで定義されているisMaleメソッドは返り値はBoolなので、このメソッドをオプショナルチェーン内で呼び出すとBool?となります。
// objectA, b, c の全てがnilではない時のみ、isMale()メソッドが呼び出される。 // isMale()の返り値はBool型なので、変数maleの型はBool?(オプショナル)となる。 let male = objectA?.b?.c?.isMale()
オプショナルチェーンでメソッドが呼び出されたかどうかをチェックする
オプショナル束縛 (optional binding) と組み合わせることで、isMale()メソッドが呼び出されたか否かによって処理を分岐させることができます。
if let male = objectA?.b?.c?.isMale() { println("isMale()が呼び出された") }else{ println("isMale()が呼び出されなかった") }
オプショナルチェーンで返り値のないメソッドが呼び出されたかどうかをチェックする
Swiftでは返り値がないメソッドも実際には空タプル () を返すので、返り値がないメソッドをオプショナルチェーン内で呼び出した場合は空タプルのオプショナル ()? を返します。
// retの型は空タプルのオプショナル ()? let ret = objectA?.b?.c?.display()
よって、このことを利用して、返り値がないメソッドが呼び出されたか否かをチェックすることができます。
if objectA?.b?.c?.display() != nil { println("display() が呼び出された") }else{ println("display() が呼び出されていない") }
オプショナルチェーンを代入先として使う
オプショナルチェーンは、値の参照やメソッドの呼び出しだけでなく、代入先としても使用することができます。
// objectA, b, c の全てがnilでは無いときのみ、代入が実行される objectA?.b?.c?.name = "suzuki"
また、この代入操作は空タプルのオプショナルを返します。よって以下のようにして代入が成功したか否かをチェックすることができます。
if (objectA?.b?.c?.name = "suzuki") != nil { println("代入できた") }else{ println("代入できなかった") }
@akio0911はこう思った。
オプショナル束縛だけを使っているとコードが煩雑になりがちですが、今回紹介したオプショナルチェーンを使うことでかなりコードをコンパクトに記述できると思います。
ちなみにオプショナルチェーンについては以下の書籍が詳しかったです!
関連記事
この記事が気に入ったら「いいね!」しよう
Twitterで更新情報をゲット!