20141128 iosチーム勉強会 my sweet swift
TRANSCRIPT
![Page 1: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/1.jpg)
My Sweet Swift
![Page 2: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/2.jpg)
Agenda
• Generics
• Enumeration
• Optional
• Appendix
![Page 3: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/3.jpg)
Agenda
• Generics
• Enumeration
• Optional
• Appendix
}準備本題
![Page 4: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/4.jpg)
Generics
![Page 5: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/5.jpg)
Generics• 型をパラメータにとる関数・データ構造
• 型情報を保ったまま、複数の型に同時に対応できる
• とは?
![Page 6: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/6.jpg)
例: 入力をそのまま返す関数
func identity(input: Int) -> Int { return input } !let number = identity(42) // Int let string = identity("Lorem ipusm") // error
![Page 7: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/7.jpg)
例: 入力をそのまま返す関数
func identity(input: Any) -> Any { return input } !let number = identity(42) // Any let string = identity("Lorem ipsum") // Any !number * 2 // error string + string // error
![Page 8: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/8.jpg)
例: 入力をそのまま返す関数
func identity<T>(input: T) -> T { return input } !let number = identity(42) // Int let string = identity("Lorem ipsum") // String !number * 2 string + string
![Page 9: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/9.jpg)
例: map
x
"\(x)"
ffunc f(x: Int) -> String { return "\(x)" }
![Page 10: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/10.jpg)
例: map
x [1, 2, 3]
"\(x)"
f
![Page 11: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/11.jpg)
例: map
x [1, 2, 3]
["1", "2", "3"]"\(x)"
f
![Page 12: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/12.jpg)
例: map
x [1, 2, 3]
["1", "2", "3"]"\(x)"
f
map([Int], Int -> String) -> [String]
![Page 13: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/13.jpg)
例: map
func f(x: Int) -> String { return "\(x)" } !func map(xs: [Int], f: Int -> String) -> [String] { var ys = [String]() for x in xs { ys.append(f(x)) } return ys } !map([1, 2, 3], f) // ["1", "2", “3"] map([1, 2, 3], { "\($0)" }) // ["1", "2", "3"]
![Page 14: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/14.jpg)
例: map
Int [Int]
[String]String
f
map([Int], Int -> String) -> [String]
![Page 15: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/15.jpg)
例: map
T [T]
[U]U
T -> U
map([T], T -> U) -> [U]
![Page 16: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/16.jpg)
例: map
func map<T, U>(xs: [T], f: T -> U) -> [U] { var ys = [U]() for x in xs { ys.append(f(x)) } return ys } !// [Int] -> [String] map([1, 2, 3], { "\($0)" }) // ["1", "2", "3"] // [Int] -> [Double] map([1, 2, 3], { $0 * 2.0 }) // [2.0, 4.0, 6.0] // [Double] -> [CGRect] map([1, 2, 3], { CGRect(x: $0, y: $0, width: 100.0, height: 100.0) })
![Page 17: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/17.jpg)
クラスの例: Stack
class Stack<T> { private var array = [T]() func push(item: T) { array.append(item) } func pop() -> T { return array.removeLast() } } !let stack = Stack<Int>() stack.push(1) stack.push(2) stack.push(3) stack.pop() // 3 stack.pop() // 2 stack.pop() // 1
![Page 18: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/18.jpg)
Enumerations
![Page 19: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/19.jpg)
Enums
enum BloodType { case A, B, O, AB } !struct Person { var bloodType: BloodType } !var p = Person(bloodType: BloodType.A) var q = Person(bloodType: .A) q.bloodType = .AB
![Page 20: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/20.jpg)
Enums
• ObjCのEnumと違って、「値」を持たない
• ex. 東西南北に整数を割り当てる意味?
• 従来通りに値を持たせることもできる
• 文字列もOK
![Page 21: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/21.jpg)
…with associated values
/// ダイアログのUI要素を指定するenum。 enum DialogItem { case TextButton(title: String, identifier: String) case GrayButton(title: String, identifier: String) case Text(String) case Title(String) case Margin(CGFloat) case Group([DialogItem]) } !let item1 = DialogItem.Margin(20) let item2 = DialogItem.Text("String")
![Page 22: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/22.jpg)
Associated Values
• enumの各状態に値を紐づけることができる
• 型が違っていてもいい
• 単なる列挙というよりは、「複数の型のどれか」を表す型になる
![Page 23: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/23.jpg)
Switchで値を展開
switch item { case let .Title(title): println("Title: \(title)") case let .Text(text): println("Text: \(text)") case let .TextButton(title: title, identifier: identifier): /// case let .GrayButton(title: title, identifier: identifier): /// case let .Group(subitems): /// default: break }
![Page 24: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/24.jpg)
例: DialogViewController
let items: [DialogViewController.DialogItem] = [ .Title("ダイアログ"), .Text("表示要素を配列で渡すだけで、自在にダイアログを作ることができます。"), .TextButton(title: "ボタン", identifier: "button1"), .Margin(60), .Group([ .Group([.Text("二段組み"), .Text("にも")]), .Group([.Text("対応"), .Text("(たぶん)")]) ]), .Group([ .TextButton(title: "ボタン", identifier: "button2"), .GrayButton(title: "ボタン", identifier: "button3"), .TextButton(title: "ボタン", identifier: "button4") ]) ] let dialog = DialogViewController(items: items, callback: nil) presentViewController(dialog, animated: true, completion: nil)
![Page 25: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/25.jpg)
簡単な例: Failable
• 「失敗するかもしれない」結果を記述する
• 失敗すればFailed、成功すればSucceeded
• 成功した場合は結果をAssociated Valueに持つ
![Page 26: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/26.jpg)
例: Failable<T>
enum Failable<T> { case Succeeded(T) // 成功したときの値 case Failed // 失敗フラグ init(_ value: T) { self = .Succeeded(value) } }
![Page 27: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/27.jpg)
例: Failable<T>
// 2で割れたら割るけど割れなかったらあきらめる(やる気のない)関数 func failableHalve(x: Int) -> Failable<Int> { if x % 2 == 0 { return .Succeeded(x / 2) } else { return .Failed } } !switch failableHalve(12) { case let .Succeeded(r): println("Answer: \(r)") default: println("Odd Number") }
![Page 28: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/28.jpg)
それって
// 2で割れたら割るけど割れなかったらあきらめる(やる気のない)関数 func failableHalve(x: Int) -> Optional<Int> { if x % 2 == 0 { return .Some(x / 2) } else { return .None } } !switch failableHalve(12) { case let .Some(r): println("Answer: \(r)") default: println("Odd Number") }
![Page 29: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/29.jpg)
Optionalなのでは?
// 2で割れたら割るけど割れなかったらあきらめる(やる気のない)関数 func failableHalve(x: Int) -> Int? { if x % 2 == 0 { return x / 2 } else { return nil } } !!if let r = failableHalve(12) { println("Answer: \(r)") } else { println("Odd Number") }
![Page 30: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/30.jpg)
Optional
![Page 31: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/31.jpg)
太古よりnullは人々を苦しめてきた
![Page 32: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/32.jpg)
Optional以前• オブジェクトとはポインタである
• 特別なアドレス(多くの場合0)をNULLと呼び、そこを指すポインタを「無効なオブジェクト」として扱う
![Page 33: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/33.jpg)
問題点• NULLを無効な値だと知っているのは実行中のプログラムとプログラマだけ
• コンパイラには他のポインタ値と区別できない
• →実行時に落ちる
• 予期せぬNULLが紛れ込まないように「気をつける」「確認する」ことしかできなかった
![Page 34: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/34.jpg)
Optionalのいいところ• 「無効な値」という概念を型にしたことで、意味論ではなく構文論として扱える
• 無効な値を扱う操作が「書けない」文法
![Page 35: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/35.jpg)
Optional<T>enum Optional<T> : Reflectable, NilLiteralConvertible { case None case Some(T) ! /// Construct a `nil` instance. init() ! /// Construct a non-\ `nil` instance that stores `some`. init(_ some: T) ! /// If `self == nil`, returns `nil`. Otherwise, returns `f(self!)`. func map<U>(f: (T) -> U) -> U? ! /// Returns a mirror that reflects `self`. func getMirror() -> MirrorType ! /// Create an instance initialized with `nil`. init(nilLiteral: ()) }
![Page 36: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/36.jpg)
Optional<T>
• 実体はGeneric Enum
• 実はちょっと嘘で、特別扱いを受けている
• cf. http://qiita.com/koher/items/5dd6ce7427e7ecff4249
• (Failable<T>と同じように)箱です
![Page 37: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/37.jpg)
Optional as 箱• 「Tかもしれない」ではなく、「Tの入る箱」
• 値に触るためには箱を開ける必要がある
• binding/coalescing/unwrapping
• 箱を開けずに操作する方法もある
• mapping/chaining
![Page 38: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/38.jpg)
Optional Binding
var optionalInt: Int? !if let int = optionalInt { // int: Int println("optionalInt was \(int)") } else { println("optionalInt was nil") } !var array = [1, 2, 3, 4] while let item = array.last { // item: Int println("\(item)") array.removeLast() }
![Page 39: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/39.jpg)
箱を開ける: Optional Binding
• 値があればtrueに評価されつつ中身を変数に束縛(bind)してくれる
• 一度に一個しかbindできないのは多少不便
![Page 40: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/40.jpg)
Optional Coalescing
optionalInt ?? 3 !// ↓と等価: optionalInt != nil ? optionalInt! : 3 !// あるいは: func coalesce<T>(lhs: T?, rhs: @autoclosure () -> T) -> T { if let lhs = lhs { return lhs } else { return rhs() } } coalesce(optionalInt, 3)
![Page 41: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/41.jpg)
箱を開ける: Optional Coalescing
• 開けられたら開ける
• 開けられなかったら開けない
• かわりにデフォルト値を返す
![Page 42: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/42.jpg)
無理矢理開ける: Forced Unwrapping
• 値があればそれが返るが、なければ落ちる
• 落ちる可能性があるので使うべきではない
• 安全が保証できるなら構わないが……
optionalInt!
![Page 43: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/43.jpg)
箱から出さずに進める方法• Optional mapping
• Optional chaining
![Page 44: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/44.jpg)
Optional Mapping
/// 3倍する関数 func triple(x: Int) -> Int { return x * 3 } !optionalInt = 2 // 以下はすべて.Some 6 optionalInt.map(triple) map(optionalInt, triple) optionalInt.map({ $0 * 3 })
![Page 45: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/45.jpg)
箱を開けない: Optional Mapping
• 箱の中から別の箱の中へ
• 値があればそれを移して別の箱(Optional)を作る
• nilならばnilを返す
![Page 46: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/46.jpg)
Optional Mapping
T
U
T -> U
map(T?, T -> U) -> U?
U?
T?
![Page 47: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/47.jpg)
Optional Chaining
class A { var b: B? } !class B { var c: C? } !class C { var i: Int = 1 } var a: A? = A() // a.b.c.iにアクセスしたい
![Page 48: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/48.jpg)
Optional Chaining
var a: A? !if let a = a { if let b = a.b { if let c = b.c { println("We finally find \(c.i)!") } } }
![Page 49: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/49.jpg)
Optional Chaining
var a: A? !if let i = a?.b?.c?.i { println("Optional chaining makes \(i)t easy.") }
![Page 50: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/50.jpg)
箱を開けない: Optional Chaining
• 失敗するかもしれない呼び出しを連鎖できる
• 失敗すればその先には進まずnil
![Page 51: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/51.jpg)
Optional Chaining
a?.b?.c?.iA?
aはA?型の変数
![Page 52: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/52.jpg)
Optional Chaining
a.bA?
A?型にbというメンバはない
×
![Page 53: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/53.jpg)
Optional Chaining
a?.b?.c?.iA?
a?.bという形にする
![Page 54: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/54.jpg)
Optional Chaining
a?.b?.c?.iA()
or
nil
aはnilかSomeのどちらか
![Page 55: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/55.jpg)
Optional Chaining
a?.b?.c?.iA()
or
nil
B?
Someならばbに触れる
![Page 56: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/56.jpg)
Optional Chaining
a?.b?.c?.iA()
or
nil nil
B?
nilならそれで終わり
![Page 57: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/57.jpg)
Optional Chaining
a?.b?.c?.iA()
or
nil nil
B?
bはB?型の変数
![Page 58: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/58.jpg)
Optional Chaining
a?.b?.c?.iA()
or
nil nil
B()
or
nil
C?
同じように分岐
![Page 59: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/59.jpg)
Optional Chaining
a?.b?.c?.iA()
or
nil nil
B()
or
nil
C()
nil
or
7
以下同文
![Page 60: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/60.jpg)
書き直してみる
extension Optional { func chain<U>(f: T -> U?) -> U? { if let s = self { return f(s) } else { return nil } } } !if let i = a.chain({ $0.b }).chain({ $0.c }).chain({ $0.i }) { println("\(i)") } !// (正確には↓だが説明は省略(結果は等しくなる)) // let k = a.chain({ $0.b.chain({ $0.c.chain({ $0.i }) }) })
![Page 61: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/61.jpg)
なぜ書き直したの?• メンバ関数以外にも使えるようにしたい
• これが今日の主役です
![Page 62: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/62.jpg)
Failable Halve
Int Int?// 2で割れたら割るけど割れなかったらあきらめる(やる気のない)関数 func failableHalve(x: Int) -> Int? { if x % 2 == 0 { return x / 2 } else { return nil } } !if let a = failableHalve(x) { println("Halve(\(x)) = \(a)") } else { println("Failed") }
![Page 63: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/63.jpg)
Failable Halve Again
Int Int?if let a = failableHalve(x) { if let b = failableHalve(a) { println("Halve^2(\(x)) = \(b)") } else { println("Failed") } } else { println("Failed") }
Int Int?
![Page 64: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/64.jpg)
Failable Halve The 3rd
Int Int?if let a = failableHalve(x) { if let b = failableHalve(a) { if let c = failableHalve(b) { println("Halve^3(\(x)) = \(c)") } else { println("Failed") } } else { println("Failed") } } else { println("Failed") }
Int Int? Int Int?
![Page 65: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/65.jpg)
Failable Halve Chaining
Int Int?if let a = failableHalve(x).chain(failableHalve).chain(failableHalve) { println("Halve^3(\(x)) = \(a)") } else { println("Failed") }
Int? Int?
![Page 66: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/66.jpg)
Failable Halve Chaining
Int Int?24 failableHalve(24) // Some 12 failableHalve(24).chain(failableHalve) // Some 6 failableHalve(24).chain(failableHalve).chain(failableHalve) // Some 3 failableHalve(24).chain(failableHalve).chain(failableHalve).chain(failableHalve) // nil !36 failableHalve(36) // Some 18 failableHalve(36).chain(failableHalve) // Some 9 failableHalve(36).chain(failableHalve).chain(failableHalve) // nil failableHalve(36).chain(failableHalve).chain(failableHalve).chain(failableHalve) // nil
Int? Int?
![Page 67: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/67.jpg)
Optional Chaining
t: T
T
![Page 68: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/68.jpg)
Optional Chaining
f(t): U?
T U?f
![Page 69: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/69.jpg)
Optional Chaining
T U?fU V?g
f(t): U?
![Page 70: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/70.jpg)
Optional Chaining
T U?
f(t).chain(g): V?
f V?g
![Page 71: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/71.jpg)
Optional Chaining
T U?
f(t).chain(g): V?
f V?g
V h W?
![Page 72: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/72.jpg)
Optional Chaining
T U?
f(t).chain(g).chain(h): W?
f V?g W?h
![Page 73: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/73.jpg)
Appendix
![Page 74: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/74.jpg)
Array Mapping
T [T]
[U]U
T -> U
map([T], T -> U) -> [U]
![Page 75: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/75.jpg)
Optional Mapping
T
U
T -> U
map( T?, T -> U) -> U?
U?
T?
![Page 76: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/76.jpg)
Optional<T>とArray<T>
• T型の値が入った箱
• mapを使えば箱の中身だけを写すことができる
![Page 77: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/77.jpg)
Optional as 状況• ところで、Optionalは「nilかもしれない」という状況(context)を表現していた
• Arrayはどんな状況を表現している?
• →「値が確定していない」
![Page 78: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/78.jpg)
Array as 状況
Kyoto
![Page 79: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/79.jpg)
目がさめると京都にいた
Kyoto
(0, 0)
![Page 80: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/80.jpg)
歩く
Kyoto
(0, 1)
(0,-1)
(1, 0)(-1,0)
![Page 81: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/81.jpg)
歩く
/// 座標 typealias Position = (Int, Int) !/// 東西南北のどこかへ歩きます func walk(from: Position) -> [Position] { let (x, y) = from return [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)] } !walk((0, 0)) // [(-1, 0), (1, 0), (0, -1), (0, 1)]
![Page 82: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/82.jpg)
さらに歩く
Kyoto
![Page 83: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/83.jpg)
さらに歩く
Kyoto
![Page 84: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/84.jpg)
Array Chaining
T [U]U
V [W][V]
![Page 85: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/85.jpg)
Array Chaining
extension Array { func chain<U>(f: Element -> [U]) -> [U] { var ys = [U]() for x in self { ys += f(x) } return ys } } !walk((0, 0)).chain(walk).chain(walk)
![Page 86: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/86.jpg)
もっと状況を!• 「値が非同期で返ってくる」も状況
![Page 87: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/87.jpg)
![Page 88: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/88.jpg)
BFTask
doHeavyJobAsync1().continueWithBlock { (task: BFTask!) -> BFTask in let result = task.result as NSString self.resultLabel1.text = result self.resultLabel2.text = "処理中..." return self.doHeavyJobAsync2(result) }.continueWithBlock { (task: BFTask!) -> BFTask in let result = task.result as NSString self.resultLabel2.text = result self.resultLabel3.text = "処理中..." return self.doHeavyJobAsync3(result) }.continueWithBlock { (task: BFTask!) -> AnyObject! in let result = task.result as NSString self.resultLabel3.text = result return nil }
![Page 89: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/89.jpg)
BFTask
private func doHeavyJobAsync2(prevResult: String) -> BFTask { var completionSource = BFTaskCompletionSource() // 5秒待ちの処理 // 実用的には、AFNetworkingのcompletionブロック等でsetResultするイメージ Util.delay(5, { completionSource.setResult(prevResult + "オワタ") }) return completionSource.task }
![Page 90: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/90.jpg)
Task<T>
class Task<T: AnyObject> { private let task: BFTask ! init(task: BFTask) { self.task = task } var result: T? { return task.result as? T } func chain<U: AnyObject>(f: (T -> Task<U>)) -> Task<U> { let newTask = task.continueWithBlock { f($0.result as T).task } return Task<U>(task: newTask) } }
![Page 91: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/91.jpg)
Taskを返す関数private func doHeavyJobAsync2(prevResult: NSString) -> Task<NSString> { let source = Source<NSString>() // 5秒待ちの処理 // 実用的には、AFNetworkingのcompletionブロック等でsetResultするイメージ delay(5, { source.setResult(prevResult + "オワタ" as NSString) }) return source.task }
![Page 92: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/92.jpg)
Task Chaining
T UU
V WV
非同期
非同期非同期
![Page 93: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/93.jpg)
Task Chaining
func heavyTask1(Void) -> Task<NSString> { return delayedTask(5) { NSLog("First Task (no params)") return "123" as NSString } } !func heavyTask2(string: NSString) -> Task<NSNumber> { return delayedTask(5) { NSLog("Second Task (param: \(string))") return NSNumber(integer: (string as String).toInt() ?? 0) } } !func heavyTask3(number: NSNumber) -> Task<NSNumber> { return delayedTask(5) { NSLog("Third Task (param: \(number))") return NSNumber(integer: number.integerValue * 2) } }
![Page 94: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/94.jpg)
Task Chaining
NSLog("Start") heavyTask1().chain(heavyTask2).chain(heavyTask3) NSLog("End")
2014-11-27 21:15:24.659 MySweetSwift[18362:314049] Start 2014-11-27 21:15:24.663 MySweetSwift[18362:314049] End 2014-11-27 21:15:29.663 MySweetSwift[18362:314049] First Task (no params) 2014-11-27 21:15:35.136 MySweetSwift[18362:314049] Second Task (param: 123) 2014-11-27 21:15:40.636 MySweetSwift[18362:314049] Third Task (param: 123)
![Page 95: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/95.jpg)
まとめ• Optionalはかわいい!
• ArrayとOptionalは似ている
• すなわち、箱であり、状況である
• 非同期処理も同じように見ることができる
• Optional Chainingのような書きかたができて、それはBFTaskに似ている
![Page 96: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/96.jpg)
参考文献
![Page 97: 20141128 iOSチーム勉強会 My Sweet Swift](https://reader030.vdocuments.pub/reader030/viewer/2022032619/55be7628bb61ebaa1f8b483f/html5/thumbnails/97.jpg)
以上