Slide 1

Slide 1 text

【 いまさら聞けない】 Swift の Optional ってなに? 2017/06/23 @fromatom

Slide 2

Slide 2 text

iOS 開発つまづきポイント Optional Delegate Autolayout ProvisioningPro fi le 突然ぶっ壊れる Xcode 突然ぶっ壊れる Xcode 突然ぶっ壊れる Xcode

Slide 3

Slide 3 text

iOS 開発つまづきポイント Optional Delegate Autolayout ProvisioningPro fi le 突然ぶっ壊れる Xcode 突然ぶっ壊れる Xcode 突然ぶっ壊れる Xcode

Slide 4

Slide 4 text

はじめに Swift の Optional が複雑( に見える) のは、 同じ記号(! と ? ) が違う意 味で使われているから たとえば、 下記で使われる ! と ? はすべて意味が違います var a: Int? = 1 var b: Int! = 2 let c: Int = a! + 10 self?.collectionView?.reloadData()

Slide 5

Slide 5 text

目次 1. Optional 2. Implicitly Unwrapped Optional 3. Optional Chaining

Slide 6

Slide 6 text

1. Optional

Slide 7

Slide 7 text

Swift での nil とは nil について知らないと Optional を理解できない Swift のnil は値・ 式の評価結果がない( もしくはエラー) を表す Swift1.x 系では do-catch と throw が無かったんや Swift にはポインタがないので厳密には空ポインタではない

Slide 8

Slide 8 text

Swift での nil とは nil を通常の値と同じように触ると虚無に飲み込まれクラッシュする 自然界にnil はないので触ったら死ぬ 他の言語と違って0 やfalse として解釈されない 虚無に型はない nil をハンドリングするために導入されたのがOptional

Slide 9

Slide 9 text

Optional Int Type まずは Int で考えます Int は整数型なので整数ではない nil は代入できない nil を代入したい場合はInt? という Optional Int Type を使う var a: Int = 0 var b: Int? = 0 a = nil // コンパイルエラー になる b = nil // 代入できる

Slide 10

Slide 10 text

Optional Int Type var a: Int = 0 var b: Int? = 0 var c: Optional = 0 // 上と同じ Int? はOptional のシンタックスシュガー Optional というクラス( 正確には enum ) があり、Generics で様々 な型を入れられる つまり、 Int と Int? は別物 ← 超重要 型が違うので同じようには使えない ← 当たり前だよね

Slide 11

Slide 11 text

Optional Int Type を Int として使いたい Int? はInt ではないのでInt として扱えない Unwrap することで使えるようになる ここで "!" が登場します Xcode に言われるがまま修正すると入ってくる謎の "!" "!" を使って Unwrap することを Force Unwrap と言います

Slide 12

Slide 12 text

Force Unwrap var optionalValue: Int? = 2000 var a: Int = optionalValue + 20 // 型が違うのでコンパイルエラー になる var b: Int = optionalValue! + 20 // 2020 になる optionalValue! の "!" で Int を取り出している もしoptionalValue の中身がnil だったら実行時クラッシュ

Slide 13

Slide 13 text

条件判定 実行時クラッシュすると困るので条件判定をします var optionalValue: Int? = 2000 if optionalValue != nil { print(optionalValue!) // ここでは "!" が必要 } if optionalValue == 1000 { // "!" を書かなくても良い print("1000 だよ") } else if optionalValue == 2000 { print("2000 だよ") // これが表示される }

Slide 14

Slide 14 text

Optional Binding 毎回 "!" 書くのは大変 if 文の then 節では nil チェックした変数を使いたいことが多い そこで Optional Binding です var optionalValue: Int? = 2000 if let value = optionalValue { // if-let で1 つの構文 print(value) //"!" が要らない } else { print("nil だったらしいよ") //optionalValue がnil なら実行される }

Slide 15

Slide 15 text

Optional Binding 複数の値を Optional Binding することもできます var optionalA: Int? = 1 var optionalB: Int? = 2 if let a = optionalA, let b = optionalB { // optionalA, optionalB が両方nil ではないときにくる print(a + b) // 3 が表示される }

Slide 16

Slide 16 text

条件式との組み合わせ optional binding した値を条件式で使える var optionalValue: Int? = 2000 if let value = optionalValue, value > 100 { print("100 より大きいよ") }

Slide 17

Slide 17 text

Nil Coalescing Operator ある Optional Type の変数がnil だった時に、 他の定数を使いたいときに 便利なやつ let value: Int = optionalValue ?? 100 optionalValue がnil なら100 が代入されます。 便利だけど多用すると右 に長くなっていくので注意。 let value: Int = optA ?? optB ?? optC ?? 100 ※Bool 値を見ているわけではないので注意

Slide 18

Slide 18 text

2. Implicitly Unwrapped Optional

Slide 19

Slide 19 text

Implicitly Unwrapped Optional 参照したら勝手に Unwrap してくれる Optional Type var a: Int = 0 var b: Int! = 0 a = nil // コンパイルエラー になる b = nil // 代入できる Int! はImplicitlyUnwrappedOptional のシンタックスシュガー var b: Int! = 0 var c: ImplicitlyUnwrappedOptional = 0 // 上と同じ

Slide 20

Slide 20 text

Implicitly Unwrapped Optional "!" で Unwrap しなくてもよい var a: Int! = 0 var b: Int = a + 20 // "!" マー クがなくてもアクセスできる! a = nil // a にnil をいれてみる var c: Int = a + 20 // 実行時にクラッシュする クラスの生成直後は nil だけど、1 度設定されたら nil になりえない変数に 使う。StoryBoard との関連(IBOutlet ) でよく使います。

Slide 21

Slide 21 text

3. Optional Chaining

Slide 22

Slide 22 text

Optional Chaining Method Chaining をする際、 途中で Optional な要素がある時に利用す る。 self?.collectionView?.reloadData() self?.navigationController?.setNavigationBarHidden(false, animated: true)

Slide 23

Slide 23 text

Optional Chaining こういう class があり、3 世代前の名前を知りたい時 class Human { var ancestor: Human? var name: String } こうやれば取れるけど、 どこかで nil が入ったらクラッシュ print(human.ancestor!.ancestor!.ancestor!.name)

Slide 24

Slide 24 text

Optional Chaining これでもいけるけど、 if let a = human.ancestor, let b = a.ancestor, let c = b.ancestor { print(c.name) } Optional Chaining を使えばこう書ける if let name = human.ancestor?.ancestor?.ancestor?.name { print(name) }

Slide 25

Slide 25 text

メソッドも実行できる self?.collectionView?.reloadData() self?.navigationController?.setNavigationBarHidden(false, animated: true) 代入もできる // 3 世代前の先祖がいたら置き換える human.ancestor?.ancestor?.ancestor? = newAncestor

Slide 26

Slide 26 text

ちょっと便利な Optional Chaining テク Void を返すメソッドを Optional Chaining で実行するとOptional を 返すようになる。 if self?.collectionView?.reloadData() != nil { //reloadData() が呼ばれたら実行される } if (human.ancestor?.ancestor?.ancestor? = newAncestor) != nil { // 代入が成功したら実行される }

Slide 27

Slide 27 text

まとめ これで Swift コー ド上で使われる様々 な意味の "!" と "?" の違いが( ふわ っと) 分かったと思います。 var a: Int? = 1 // Optional var b: Int! = 2 // Implicitly Unwrapped Optional var c: Int = a! + 10 // Force Unwrap self?.collectionView?.reloadData() // Optional Chaining

Slide 28

Slide 28 text

参考文献 1. 詳解 Swift 改訂版 2016 年 1 月 1 日 初版第一刷発行 http://amzn.asia/eeKqCsH Swift3 系はこちら:http://amzn.asia/4IXtxem 2. どこよりも分かりやすい Swift の "?" と "!" http://qiita.com/maiki055/items/b24378a3707bd35a31a8