Slide 1

Slide 1 text

打開 Combine 的引擎蓋看看 SWIFT, COMBINE, REACTIVE IPLAYGROUND 2020 游諭 What’s under the hood?

Slide 2

Slide 2 text

游諭(@ytyubox) 
 ⾃學程式 iOS - 2018 iT 邦幫忙鐵⼈賽: 
 30 天了解 Swift 的 Combine 
 30 天從 Swift 學會 Objective-C $> whoami 2

Slide 3

Slide 3 text

Agenda Short Introductions 簡單的 Combine 應⽤ combine 的⾓⾊ Behavior test 更進階的 Combine 3 ⽬錄

Slide 4

Slide 4 text

Agenda Short Introductions 簡單的 Combine 應⽤ combine 的⾓⾊ Behavior test 更進階的 Combine 4 ⽬錄 50 % +

Slide 5

Slide 5 text

5 開始之前

Slide 6

Slide 6 text

6 ,這個 Session 將會 介紹如何入⾨ Combine 並不包含解釋 Framework 內部原始碼 開始之前

Slide 7

Slide 7 text

Short Introductions 7

Slide 8

Slide 8 text

8

Slide 9

Slide 9 text

9 SwiftUI

Slide 10

Slide 10 text

10 Combine SwiftUI

Slide 11

Slide 11 text

RxSwift 11 https://github.com/ReactiveX https://github.com/ReactiveCocoa/ReactiveSwift https://developer.apple.com/videos/wwdc2019 Combine

Slide 12

Slide 12 text

12 https://github.com/ReactiveX https://github.com/ReactiveCocoa/ReactiveSwift https://developer.apple.com/videos/wwdc2019 Functional Reactive Programming Combine RxSwift

Slide 13

Slide 13 text

13 A unified, declarative API for 
 processing values over time. By WWDC 2019: Introducing Combine Functional Reactive Programming Combine

Slide 14

Slide 14 text

14 A unified, declarative API for 
 processing values over time. By WWDC 2019: Introducing Combine Functional Reactive Programming Combine

Slide 15

Slide 15 text

15 A unified, declarative API for 
 processing values over time. Generic Composition f i rst Request driven type safe By WWDC 2019: Introducing Combine Combine

Slide 16

Slide 16 text

打開 Combine 會發現什麼? 16

Slide 17

Slide 17 text

17 打開 Combine 發現了⼀隻貓

Slide 18

Slide 18 text

Asynchronous Programming 18

Slide 19

Slide 19 text

來⾃ Apple / Combine 19 透過組合處理事件的運算⼦來定制異步事件的應對⽅式。

Slide 20

Slide 20 text

來⾃ Apple / Combine 20 透過組合處理事件的運算⼦來定制異步事件的應對⽅式。

Slide 21

Slide 21 text

來⾃ Apple / Combine 21 透過組合處理事件的運算⼦來定制異步事件的應對⽅式。 注意 Apple 這裡的非同步不是指 Dispatch framework

Slide 22

Slide 22 text

22 asynchronous programing 非同步程式設計

Slide 23

Slide 23 text

Property Observers ( set / didSet ) Target / Action ( @IBAction ) Notification Center Ad-hoc Callbacks 23 asynchronous programing 非同步程式設計 URLSession.dataTask(with:, completionHandler:) Key-Value Observing

Slide 24

Slide 24 text

24 Key-Value Observing 複習⼀下

Slide 25

Slide 25 text

25 class KVOTarget: NSObject { @objc dynamic var value = 0 } let target = KVOTarget() var captured = [Int?]() let kvoToken = target.observe(\.value, options: .new) { (target, change) in captured.append(change.newValue) } XCTAssertEqual(captured, []) target.value = 1 target.value = 2 XCTAssertEqual(captured, [1, 2]) kvoToken.invalidate() target.value = 3 XCTAssertEqual(captured, [1, 2]) Key-Value Observing 複習⼀下

Slide 26

Slide 26 text

26 class KVOTarget: NSObject { @objc dynamic var value = 0 } let target = KVOTarget() var captured = [Int?]() let kvoToken = target.observe(\.value, options: .new) { (target, change) in captured.append(change.newValue) } XCTAssertEqual(captured, []) target.value = 1 target.value = 2 XCTAssertEqual(captured, [1, 2]) kvoToken.invalidate() target.value = 3 XCTAssertEqual(captured, [1, 2]) Key-Value Observing 複習⼀下

Slide 27

Slide 27 text

27 class KVOTarget: NSObject { @objc dynamic var value = 0 } let target = KVOTarget() var captured = [Int?]() let kvoToken = target.observe(\.value, options: .new) { (target, change) in captured.append(change.newValue) } XCTAssertEqual(captured, []) target.value = 1 target.value = 2 XCTAssertEqual(captured, [1, 2]) kvoToken.invalidate() target.value = 3 XCTAssertEqual(captured, [1, 2]) Key-Value Observing 複習⼀下

Slide 28

Slide 28 text

28 class KVOTarget: NSObject { @objc dynamic var value = 0 } let target = KVOTarget() var captured = [Int?]() let kvoToken = target.observe(\.value, options: .new) { (target, change) in captured.append(change.newValue) } XCTAssertEqual(captured, []) target.value = 1 target.value = 2 XCTAssertEqual(captured, [1, 2]) kvoToken.invalidate() target.value = 3 XCTAssertEqual(captured, [1, 2]) Key-Value Observing 複習⼀下

Slide 29

Slide 29 text

簡單 Combine 應⽤ 29

Slide 30

Slide 30 text

30 import Combine

Slide 31

Slide 31 text

31 URLSession.shared.dataTaskPublisher(for: aURL) import Combine

Slide 32

Slide 32 text

32 URLSession.shared.dataTaskPublisher(for: aURL) Publisher import Combine

Slide 33

Slide 33 text

33 URLSession.shared.dataTaskPublisher(for: aURL) .map(\.data) .decode(type: MyModel.self, decoder: JSONDecoder()) Publisher import Combine

Slide 34

Slide 34 text

34 URLSession.shared.dataTaskPublisher(for: aURL) .map(\.data) .decode(type: MyModel.self, decoder: JSONDecoder()) .sink(receiveCompletion: self.receiveCompletionMethod, 
 receiveValue: self.receiveValueMethod) AnyCancellable import Combine

Slide 35

Slide 35 text

35 import Combine func greet(person: String) throws -> String { let greeting = "Hello, " + person + "!" return greeting }

Slide 36

Slide 36 text

36 func greetPublisher(person: String) -> AnyPublisher { return Just(person) .prepend("Hello, ") .append("!") .reduce("", +) .eraseToAnyPublisher() } func greet(person: String) throws -> String { let greeting = "Hello, " + person + "!" return greeting } import Combine

Slide 37

Slide 37 text

Combine ⾓⾊ 37

Slide 38

Slide 38 text

38 import Combine protocol Publisher { associatedtype Output associatedtype Failure : Error func receive(subscriber: S) where Self.Failure == S.Failure, Self.Output == S.Input }

Slide 39

Slide 39 text

39 import Combine protocol Publisher { ... }

Slide 40

Slide 40 text

40 import Combine protocol Publisher { ... } protocol Subscriber { associatedtype Input associatedtype Failure : Error func receive(subscription: Subscription) func receive(_ input: Self.Input) -> Subscribers.Demand func receive(completion: Subscribers.Completion) }

Slide 41

Slide 41 text

41 import Combine protocol Publisher { ... } protocol Subscriber { ... }

Slide 42

Slide 42 text

protocol Publisher { ... } protocol Subscriber { ... } 42 Subscriber Publisher import Combine

Slide 43

Slide 43 text

Subscriber Publisher 43

Slide 44

Slide 44 text

Subscriber Publisher 44

Slide 45

Slide 45 text

Subscriber Publisher 45

Slide 46

Slide 46 text

Subscriber Publisher 46

Slide 47

Slide 47 text

Subscriber Publisher 47

Slide 48

Slide 48 text

Subscriber Publisher 48

Slide 49

Slide 49 text

Subscriber 49

Slide 50

Slide 50 text

50 Combine Pattern From WWDC 2019 - Introducing Combine

Slide 51

Slide 51 text

51 Combine Pattern From WWDC 2019 - Introducing Combine 來⾃與 Introducing Combine https://developer.apple.com/videos/play/wwdc2019/722/

Slide 52

Slide 52 text

Subscriber Publisher subscribe( ) is attached Publisher Subscriber Combine Pattern From WWDC 2019 - Introducing Combine 52

Slide 53

Slide 53 text

Subscriber Publisher subscribe( ) is attached Publisher Subscriber Subscription receive(subscription: ) sends Publisher Subscription Combine Pattern From WWDC 2019 - Introducing Combine 53

Slide 54

Slide 54 text

Subscriber Publisher subscribe( ) is attached Publisher Subscriber request(_: Demand) requests N values Subscriber Subscription receive(subscription: ) sends Publisher Subscription Combine Pattern From WWDC 2019 - Introducing Combine 54

Slide 55

Slide 55 text

Subscriber Publisher subscribe( ) is attached Publisher Subscriber receive(_: Input) sends N values or less Publisher request(_: Demand) requests N values Subscriber Subscription receive(subscription: ) sends Publisher Subscription Combine Pattern From WWDC 2019 - Introducing Combine 55

Slide 56

Slide 56 text

Subscriber Publisher subscribe( ) is attached Publisher Subscriber receive(_: Input) sends N values or less Publisher receive(completion:) sends completion Publisher request(_: Demand) requests N values Subscriber Subscription receive(subscription: ) sends Publisher Subscription Combine Pattern From WWDC 2019 - Introducing Combine 56

Slide 57

Slide 57 text

57 如果對⼀個 Publisher 重複 Subscribe 呢?

Slide 58

Slide 58 text

Publisher Subscriber 58 Subscriber No. 2

Slide 59

Slide 59 text

Publisher Subscriber 59 Subscriber No. 2

Slide 60

Slide 60 text

Publisher Subscriber 60 Subscriber No. 2

Slide 61

Slide 61 text

Publisher Subscriber 61 Subscriber No. 2

Slide 62

Slide 62 text

Publisher Subscriber 62 Subscriber No. 2 Copied Publisher

Slide 63

Slide 63 text

Publisher Subscriber 63 Subscriber No. 2 Copied Publisher

Slide 64

Slide 64 text

Publisher Subscriber 64 Subscriber No. 2 Copied Publisher

Slide 65

Slide 65 text

Publisher Subscriber 65 Subscriber No. 2 Copied Publisher

Slide 66

Slide 66 text

Subscriber Publisher subscribe( ) receive(_: Input) sends N values or less Publisher receive(completion:) sends completion Publisher request(_: Demand) Subscription receive(subscription: ) is attached Publisher Subscriber requests N values Subscriber sends Publisher Subscription Combine Pattern From WWDC 2019 - Introducing Combine 66

Slide 67

Slide 67 text

receive(subscription: ) Publisher 67 Subscriber subscribe( ) request(_: Demand) receive(_: Input) receive(completion:) Subscription subscribe( ) receive(_: Input) sends N values or less receive(completion:) sends completion request(_: Demand) Subscription Combine Pattern From my perspective Subscription Subscription is attached Publisher Subscriber requests N values Subscriber sends Publisher Subscription

Slide 68

Slide 68 text

Subscription Publisher Subscriber 68

Slide 69

Slide 69 text

Combine Operator 69

Slide 70

Slide 70 text

Publisher Publisher Mapper 70 Operator

Slide 71

Slide 71 text

71 Operator 其實是 decorator pattern

Slide 72

Slide 72 text

Publisher Operator class Operator: Publisher { let concrete: Publisher } is a has a 72 decorator pattern

Slide 73

Slide 73 text

client decor 1 driver decor 2 action 73 decorator pattern

Slide 74

Slide 74 text

client decor 1 driver decor 2 action addBehavior 74 decorator pattern

Slide 75

Slide 75 text

client decor 1 driver decor 2 action action 75 decorator pattern addBehavior

Slide 76

Slide 76 text

client decor 1 driver decor 2 action action action 76 decorator pattern addBehavior

Slide 77

Slide 77 text

addBehavior client decor 1 driver decor 2 action action action 77 decorator pattern addBehavior

Slide 78

Slide 78 text

client decor 1 driver decor 2 action action action 78 decorator pattern addBehavior addBehavior addBehavior

Slide 79

Slide 79 text

Mazinger Z: a Japanese super robot manga series written and illustrated by Go Naga Has a Man, is a Man. 79 無敵鐵⾦剛

Slide 80

Slide 80 text

80 Behavior tests

Slide 81

Slide 81 text

81 AnyCancellable deinit 會⾃動 Cancel

Slide 82

Slide 82 text

82 let subject = PassthroughSubject() var received = [Event]() weak var weakCancellable: AnyCancellable? do { let anyCancellable = subject .sink(event: { e in received.append(e) } ) weakCancellable = anyCancellable subject.send(1) } XCTAssertNil(weakCancellable) subject.send(2) XCTAssertEqual(received, [1]) AnyCancellable deinit 會⾃動 Cancel

Slide 83

Slide 83 text

83 let subject = PassthroughSubject() var received = [Event]() weak var weakCancellable: AnyCancellable? do { let anyCancellable = subject .sink(event: { e in received.append(e) } ) weakCancellable = anyCancellable subject.send(1) } XCTAssertNil(weakCancellable) subject.send(2) XCTAssertEqual(received, [1]) AnyCancellable deinit 會⾃動 Cancel

Slide 84

Slide 84 text

84 let subject = PassthroughSubject() var received = [Event]() weak var weakCancellable: AnyCancellable? do { let anyCancellable = subject .sink(event: { e in received.append(e) } ) weakCancellable = anyCancellable subject.send(1) } XCTAssertNil(weakCancellable) subject.send(2) XCTAssertEqual(received, [1]) AnyCancellable deinit 會⾃動 Cancel

Slide 85

Slide 85 text

85 let subject = PassthroughSubject() var received = [Event]() weak var weakCancellable: AnyCancellable? do { let anyCancellable = subject .sink(event: { e in received.append(e) } ) weakCancellable = anyCancellable subject.send(1) } XCTAssertNil(weakCancellable) subject.send(2) XCTAssertEqual(received, [1]) AnyCancellable deinit 會⾃動 Cancel

Slide 86

Slide 86 text

86 let subject = PassthroughSubject() var received = [Event]() weak var weakCancellable: AnyCancellable? do { let anyCancellable = subject .sink(event: { e in received.append(e) } ) weakCancellable = anyCancellable subject.send(1) } XCTAssertNil(weakCancellable) subject.send(2) XCTAssertEqual(received, [1]) AnyCancellable deinit 會⾃動 Cancel

Slide 87

Slide 87 text

87 let subject = PassthroughSubject() var received = [Event]() weak var weakCancellable: AnyCancellable? do { let anyCancellable = subject .sink(event: { e in received.append(e) } ) weakCancellable = anyCancellable subject.send(1) } XCTAssertNil(weakCancellable) subject.send(2) XCTAssertEqual(received, [1]) AnyCancellable deinit 會⾃動 Cancel

Slide 88

Slide 88 text

88 NSKeyValueObservation deinit 也會⾃動 Cancel

Slide 89

Slide 89 text

89 let target = KVOTarget() var captured = [Int?]() weak var weakKvoToken: NSKeyValueObservation? do { let token = target.observe(\.value, options: .new) { (target, change) in captured.append(change.newValue) } weakKvoToken = token target.value = 1 target.value = 2 XCTAssertEqual(captured, [1, 2]) } XCTAssertNil(weakKvoToken) target.value = 3 XCTAssertEqual(captured, [1, 2]) NSKeyValueObservation deinit 也會⾃動 Cancel

Slide 90

Slide 90 text

let target = KVOTarget() var captured = [Int?]() weak var weakKvoToken: NSKeyValueObservation? do { let token = target.observe(\.value, options: .new) { (target, change) in captured.append(change.newValue) } weakKvoToken = token target.value = 1 target.value = 2 XCTAssertEqual(captured, [1, 2]) } XCTAssertNil(weakKvoToken) target.value = 3 XCTAssertEqual(captured, [1, 2]) 90 NSKeyValueObservation deinit 也會⾃動 Cancel

Slide 91

Slide 91 text

let target = KVOTarget() var captured = [Int?]() weak var weakKvoToken: NSKeyValueObservation? do { let token = target.observe(\.value, options: .new) { (target, change) in captured.append(change.newValue) } weakKvoToken = token target.value = 1 target.value = 2 XCTAssertEqual(captured, [1, 2]) } XCTAssertNil(weakKvoToken) target.value = 3 XCTAssertEqual(captured, [1, 2]) 91 NSKeyValueObservation deinit 也會⾃動 Cancel

Slide 92

Slide 92 text

92 使⽤ Publisher.subscribe 會 Retain Sink

Slide 93

Slide 93 text

93 let subject = PassthroughSubject() var received = [Event]() weak var weakSink: Subscribers.Sink? do { let sink = Subscribers.Sink{ received.append(.value($0)) } weakSink = sink subject.subscribe(sink) subject.send(1) } XCTAssertNotNil(weakSink) subject.send(2) weakSink?.cancel() XCTAssertNil(weakSink) subject.send(3) XCTAssertEqual(received, [1, 2]) 使⽤ Publisher.subscribe 會 Retain Sink

Slide 94

Slide 94 text

94 let subject = PassthroughSubject() var received = [Event]() weak var weakSink: Subscribers.Sink? do { let sink = Subscribers.Sink{ received.append(.value($0)) } weakSink = sink subject.subscribe(sink) subject.send(1) } XCTAssertNotNil(weakSink) subject.send(2) weakSink?.cancel() XCTAssertNil(weakSink) subject.send(3) XCTAssertEqual(received, [1, 2]) 使⽤ Publisher.subscribe 會 Retain Sink

Slide 95

Slide 95 text

95 let subject = PassthroughSubject() var received = [Event]() weak var weakSink: Subscribers.Sink? do { let sink = Subscribers.Sink{ received.append(.value($0)) } weakSink = sink subject.subscribe(sink) subject.send(1) } XCTAssertNotNil(weakSink) subject.send(2) weakSink?.cancel() XCTAssertNil(weakSink) subject.send(3) XCTAssertEqual(received, [1, 2]) 使⽤ Publisher.subscribe 會 Retain Sink

Slide 96

Slide 96 text

96 let subject = PassthroughSubject() var received = [Event]() weak var weakSink: Subscribers.Sink? do { let sink = Subscribers.Sink{ received.append(.value($0)) } weakSink = sink subject.subscribe(sink) subject.send(1) } XCTAssertNotNil(weakSink) subject.send(2) weakSink?.cancel() XCTAssertNil(weakSink) subject.send(3) XCTAssertEqual(received, [1, 2]) 使⽤ Publisher.subscribe 會 Retain Sink

Slide 97

Slide 97 text

97 let subject = PassthroughSubject() var received = [Event]() weak var weakSink: Subscribers.Sink? do { let sink = Subscribers.Sink{ received.append(.value($0)) } weakSink = sink subject.subscribe(sink) subject.send(1) } XCTAssertNotNil(weakSink) subject.send(2) weakSink?.cancel() XCTAssertNil(weakSink) subject.send(3) XCTAssertEqual(received, [1, 2]) 使⽤ Publisher.subscribe 會 Retain Sink

Slide 98

Slide 98 text

98 let subject = PassthroughSubject() var received = [Event]() weak var weakSink: Subscribers.Sink? do { let sink = Subscribers.Sink{ received.append(.value($0)) } weakSink = sink subject.subscribe(sink) subject.send(1) } XCTAssertNotNil(weakSink) subject.send(2) weakSink?.cancel() XCTAssertNil(weakSink) subject.send(3) XCTAssertEqual(received, [1, 2]) 使⽤ Publisher.subscribe 會 Retain Sink

Slide 99

Slide 99 text

更進階的 Combine 99

Slide 100

Slide 100 text

在開始之前:習慣 Value over time 100

Slide 101

Slide 101 text

複習⼀下 ”國中物理“ 直線等加速度運動圖形 101

Slide 102

Slide 102 text

複習⼀下 ”國中物理“ 直線等加速度運動圖形 102 時間 速 度 時間 位 移 時間 加 速 度

Slide 103

Slide 103 text

複習⼀下 ”國中物理“ 直線等加速度運動圖形 103 時間 速 度 時間 位 移 時間 加 速 度

Slide 104

Slide 104 text

104 彈珠圖 marble diagram 事件 Event 截⽌ Completion ❌ Error 事件流 Stream

Slide 105

Slide 105 text

105 彈珠圖 marble diagram 事件流 Stream ❌ Error

Slide 106

Slide 106 text

106 Publisher Subscribe 多次

Slide 107

Slide 107 text

107 Subscriber Subscriber Publisher Publisher Subscribe 多次

Slide 108

Slide 108 text

108 Subscriber Subscriber Publisher Publisher Subscribe 多次

Slide 109

Slide 109 text

109 Subscriber Subscriber Publisher Publisher Subscribe 多次

Slide 110

Slide 110 text

110 Subscriber Subscriber Publisher Publisher Subscribe 多次

Slide 111

Slide 111 text

111 Subscriber Subscriber Publisher Subject Publisher Subscribe 多次

Slide 112

Slide 112 text

112 Subscriber Subscriber Publisher Subject Publisher Subscribe 多次

Slide 113

Slide 113 text

113 Subscriber Subscriber Publisher Subject Publisher Subscribe 多次

Slide 114

Slide 114 text

114 Subscriber Subscriber Publisher Subject Publisher Subscribe 多次

Slide 115

Slide 115 text

115 Subscriber Subscriber Publisher Subject Publisher Subscribe 多次

Slide 116

Slide 116 text

116 Subscriber Subscriber Publisher Subject Publisher Subscribe 多次

Slide 117

Slide 117 text

117 Hot / Cold Publisher

Slide 118

Slide 118 text

118

Slide 119

Slide 119 text

119 Cold Publisher

Slide 120

Slide 120 text

Subscriber Publisher 120 Cold Publisher

Slide 121

Slide 121 text

Subscriber Publisher 121 Cold Publisher

Slide 122

Slide 122 text

Subscriber Publisher 122 Cold Publisher

Slide 123

Slide 123 text

Subscriber Publisher 123 Cold Publisher

Slide 124

Slide 124 text

124 Hot Publisher

Slide 125

Slide 125 text

Publisher 125 Hot Publisher

Slide 126

Slide 126 text

Publisher 126 Hot Publisher

Slide 127

Slide 127 text

Subscriber Publisher 127 Hot Publisher

Slide 128

Slide 128 text

Subscriber Publisher 128 Hot Publisher

Slide 129

Slide 129 text

Subscriber Publisher 129 Hot Publisher

Slide 130

Slide 130 text

Subscriber Publisher 130 Hot Publisher

Slide 131

Slide 131 text

131 Passthrough Subject CurrentValue Subject

Slide 132

Slide 132 text

132 Passthrough Subject CurrentValue Subject

Slide 133

Slide 133 text

133 Passthrough Subject CurrentValue Subject

Slide 134

Slide 134 text

134 Passthrough Subject CurrentValue Subject

Slide 135

Slide 135 text

135 Passthrough Subject CurrentValue Subject

Slide 136

Slide 136 text

136 Passthrough Subject CurrentValue Subject

Slide 137

Slide 137 text

137 let subjectA = PassthroughSubject() let scanB = subjectA.scan(0, +) var receivedC = [Event]() let sinkC = scanB.sink{ e in receivedC.append(e) } subjectA.send(1...2) var receivedD = [Event]() let sinkD = scanB.sink{ e in receivedD.append(e) } subjectA.send(3...4) XCTAssertEqual(receivedC, [1, 3, 6, 10]) // 0 + 1...4 XCTAssertEqual(receivedD, [3, 7]) // 0 + 3...4

Slide 138

Slide 138 text

138 let subjectA = PassthroughSubject() let scanB = subjectA.scan(0, +) var receivedC = [Event]() let sinkC = scanB.sink{ e in receivedC.append(e) } subjectA.send(1...2) var receivedD = [Event]() let sinkD = scanB.sink{ e in receivedD.append(e) } subjectA.send(3...4) XCTAssertEqual(receivedC, [1, 3, 6, 10]) // 0 + 1...4 XCTAssertEqual(receivedD, [3, 7]) // 0 + 3...4

Slide 139

Slide 139 text

139 let subjectA = PassthroughSubject() let scanB = subjectA.scan(0, +) var receivedC = [Event]() let sinkC = scanB.sink{ e in receivedC.append(e) } subjectA.send(1...2) var receivedD = [Event]() let sinkD = scanB.sink{ e in receivedD.append(e) } subjectA.send(3...4) XCTAssertEqual(receivedC, [1, 3, 6, 10]) // 0 + 1...4 XCTAssertEqual(receivedD, [3, 7]) // 0 + 3...4

Slide 140

Slide 140 text

FlatMap 140

Slide 141

Slide 141 text

之前複習⼀下 向量投影(內積) 141 FlatMap

Slide 142

Slide 142 text

142 FlatMap

Slide 143

Slide 143 text

143 FlatMap

Slide 144

Slide 144 text

144 FlatMap

Slide 145

Slide 145 text

145 FlatMap

Slide 146

Slide 146 text

146 FlatMap

Slide 147

Slide 147 text

Error handling By Catch 147 Publisher Subscriber Catch

Slide 148

Slide 148 text

Error handling By Catch 148 Publisher Subscriber Catch

Slide 149

Slide 149 text

Error handling By Catch 149 Publisher Subscriber Catch

Slide 150

Slide 150 text

Error handling By Catch 150 Publisher Subscriber Catch

Slide 151

Slide 151 text

Error handling By Catch 151 Subscriber Catch

Slide 152

Slide 152 text

Error handling By Catch 152 Subscriber Catch Recovery Publisher

Slide 153

Slide 153 text

Error handling By Catch 153 Subscriber Catch Recovery Publisher

Slide 154

Slide 154 text

Error handling By Catch 154 Subscriber Catch Recovery Publisher

Slide 155

Slide 155 text

Error From TryMap 155 Publisher Subscriber Catch TryMap

Slide 156

Slide 156 text

Error From TryMap 156 Publisher Subscriber Catch TryMap

Slide 157

Slide 157 text

Error From TryMap 157 Publisher Subscriber Catch TryMap

Slide 158

Slide 158 text

Error From TryMap 158 Publisher Subscriber Catch TryMap

Slide 159

Slide 159 text

Error From TryMap 159 Publisher Subscriber Catch TryMap

Slide 160

Slide 160 text

Error From TryMap 160 Publisher Subscriber Catch TryMap

Slide 161

Slide 161 text

Error From TryMap 161 Subscriber Catch

Slide 162

Slide 162 text

Error From TryMap 162 Subscriber Catch Recovery Publisher

Slide 163

Slide 163 text

Error From TryMap 163 Subscriber Catch Recovery Publisher

Slide 164

Slide 164 text

Error From TryMap 164 Subscriber Catch Recovery Publisher

Slide 165

Slide 165 text

使⽤ FlatMap 導流 165 Publisher Subscriber FlatMap

Slide 166

Slide 166 text

使⽤ FlatMap 導流 166 Publisher Subscriber FlatMap

Slide 167

Slide 167 text

使⽤ FlatMap 導流 167 Publisher Subscriber Catch TryMap FlatMap Catch TryMap

Slide 168

Slide 168 text

使⽤ FlatMap 導流 168 Publisher Subscriber Catch TryMap FlatMap Catch TryMap

Slide 169

Slide 169 text

使⽤ FlatMap 導流 169 Publisher Subscriber Catch TryMap FlatMap Catch TryMap

Slide 170

Slide 170 text

使⽤ FlatMap 導流 170 Publisher Subscriber Catch FlatMap Catch Recovery Publisher

Slide 171

Slide 171 text

使⽤ FlatMap 導流 171 Publisher Subscriber FlatMap

Slide 172

Slide 172 text

使⽤ FlatMap 導流 172 Publisher Subscriber FlatMap

Slide 173

Slide 173 text

使⽤ FlatMap 導流 173 Publisher Subscriber FlatMap

Slide 174

Slide 174 text

使⽤ FlatMap 導流 174 Publisher Subscriber FlatMap

Slide 175

Slide 175 text

使⽤ FlatMap 導流 175 Publisher Subscriber FlatMap Catch TryMap Catch TryMap

Slide 176

Slide 176 text

使⽤ FlatMap 導流 176 Publisher Subscriber FlatMap Catch TryMap Catch TryMap

Slide 177

Slide 177 text

使⽤ FlatMap 導流 177 Publisher Subscriber FlatMap

Slide 178

Slide 178 text

使⽤ FlatMap 導流 178 Publisher Subscriber FlatMap ✅

Slide 179

Slide 179 text

聽完這個 Session 之後呢? 179

Slide 180

Slide 180 text

Apple/Swift Combine Extension 180 https://github.com/apple/swift/tree/main/stdlib/public/Darwin/Foundation

Slide 181

Slide 181 text

Reactive Programming Taiwan (RxSwift/Combine) 加入 Telegram 台灣社群 181

Slide 182

Slide 182 text

加入 Combine Community 182

Slide 183

Slide 183 text

183 watchOS tvOS iOS macOS Combine

Slide 184

Slide 184 text

184 watchOS tvOS iOS macOS Linux WASI

Slide 185

Slide 185 text

Apple Combine Documents WWDC 2019 Session 722, Session 721 cocoawithlove by Matt Gallagher - 22 short tests of Combine 
 https://www.cocoawithlove.com/blog/twenty-two-short-tests-of-combine-part-1.html OpenCombine 
 https://github.com/OpenCombine ReactiveX.io 
 http://reactivex.io/ ReactiveCocoa.io 
 https://reactivecocoa.io/ 參考資料 185

Slide 186

Slide 186 text

結論 186

Slide 187

Slide 187 text

187 Combine 酷嗎?

Slide 188

Slide 188 text

188 Combine 酷嗎?

Slide 189

Slide 189 text

189 Combine 酷嗎? Combine 好學嗎?

Slide 190

Slide 190 text

190 Combine 酷嗎? Combine 好學嗎? ✅

Slide 191

Slide 191 text

191 Combine 酷嗎? Combine 好學嗎? ✅ Combine 好⽤嗎?

Slide 192

Slide 192 text

192 Combine 酷嗎? Combine 好學嗎? ✅ Combine 好⽤嗎?

Slide 193

Slide 193 text

193 ✅ Combine