Slide 1

Slide 1 text

EVERYDAY REACTIVE 毎⽇日リアクティブ Agnes Vasarhelyi @vasarhelyia
 ! Ustream (IBM Cloud Video)

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

"Reactive programming manages asynchronous data flows between sources of data and components that need to react to that data." MATT GALLAGHER, COCOAWITHLOVE.COM

Slide 4

Slide 4 text

• Reduces state • Less, but more concise code • Easier to read

Slide 5

Slide 5 text

IS THERE A FRAMEWORK FOR THAT? There are plenty.

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

WHEN DO I APPLY IT? Depends on complexity.

Slide 8

Slide 8 text

WHERE DO I APPLY IT? • MVVM • async ops

Slide 9

Slide 9 text

OBSERVATION

Slide 10

Slide 10 text

let (signal, observer) = Signal.pipe() signal.observeValues { animal in print( "value: \(animal)") } observer.sendNext(value: "") observer.sendNext(value: "") > value: > value: ReactiveSwift (RAC)

Slide 11

Slide 11 text

LET'S REDUCE SOME STATE

Slide 12

Slide 12 text

var loading: Bool var userLoggedIn: Bool var didShowAlert: Bool var loading = reactive(userLoggedIn) && reactive(didShowAlert) 23 STATE 22 STATE

Slide 13

Slide 13 text

TRANSFORM / COMBINE

Slide 14

Slide 14 text

let userLoggedIn = PublishSubject() let didLoadContent = PublishSubject() let loading = Observable.combineLatest(userLoggedIn, didLoadContent) { !($0 && $1) } loading.subscribe(onNext: { print("loading: \($0)") }) userLoggedIn.onNext(false) didLoadContent.onNext(false) userLoggedIn.onNext(true) didLoadContent.onNext(true) > loading: true > loading: true > loading: false RxSwift

Slide 15

Slide 15 text

SIMPLIFY / UNIFY ASYNC OPERATIONS

Slide 16

Slide 16 text

let catButton = UIButton(title: "") let url = URL(string: "http://catfacts-api.appspot.com/api/facts? number=1") let catFact = URLSession.shared.rx.json(url:url!) .map( { return "\(parsedCatFact($0))" }) Observable.combineLatest(catButton.rx.tap, catFact) { c, fact in "\(c) \(fact)" }.subscribe(onNext: { print("\($0)") }) > : Cats can be right-pawed or left-pawed. > : In 1987 cats overtook dogs as the number one pet in America. RxSwift

Slide 17

Slide 17 text

TRADE-OFFS, COMPLICATIONS

Slide 18

Slide 18 text

1. DEBUGGING

Slide 19

Slide 19 text

HOW TO HELP IT?

Slide 20

Slide 20 text

func logAnimals() { let animal = MutableProperty("") let animalStream = animal.producer.logEvents(identifier: "") animalStream.start() animal.value = "" } [] starting fileName: (...)/A.swift, functionName: logAnimals(), lineNumber: 16 [] value fileName: (...)/A.swift, functionName: logAnimals(), lineNumber: 16 [] started fileName: (...)/A.swift, functionName: logAnimals(), lineNumber: 16 [] value fileName: (...)/A.swift, functionName: logAnimals(), lineNumber: 16 ... ReactiveSwift (RAC)

Slide 21

Slide 21 text

2. "FANCY KVO"

Slide 22

Slide 22 text

viewModel.title.observeNext { [weak self] v in self?.titleLabel.text = v self?.refreshButton.enabled = true self?.canRefresh = true }) func update() { if (!self.canRefresh) return; ... } Bond

Slide 23

Slide 23 text

viewModel.title.bind(to: titleLabel) Bond

Slide 24

Slide 24 text

viewModel.title.map { n -> Bool in return n != nil }.bind(to: refreshButton.reactive.isEnabled) Bond

Slide 25

Slide 25 text

viewModel.title.bind(to: titleLabel) viewModel.title .bidirectionalBind(to: titleTextField.reactive.bnd_text) Bond

Slide 26

Slide 26 text

3. INJECT SIDE EFFECTS CAREFULLY

Slide 27

Slide 27 text

let catFact = URLSession.shared.rx.json(url:url!) .map( { return "\(parsedCatFact($0))" }) .do(onNext: { _ in print("EFFECT") }) catFact.subscribe(onNext: { print("1. : \($0)") }) catFact.subscribe(onNext: { print("2. : \($0)") }) > EFFECT > 1. : Most cats adore sardines. > EFFECT > 2. : Cats take between 20-40 breaths per minute. RxSwift

Slide 28

Slide 28 text

... .do(onNext: { fact in Analytics.trackEvent("cat fact generated: \(fact)") })

Slide 29

Slide 29 text

4. AVOID CHAOS

Slide 30

Slide 30 text

Thread 1 eraseButton.reactive.tap.onNext( { stateManager.items.remove($0) }) Thread 2 apiResponse.onNext ( { stateManager.items.append($0) }) eraseButton.reactive.tap.onNext( { stateManager.removeItem($0) }).onScheduler(MainScheduler) apiResponse.onNext ( { stateManager.appendItem($0) }).onScheduler(BackgroundScheduler) immutability + schedulers =

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

... .ignoreNil() .flatMapLatest { $0.unwrap } .collect() .first() .filter(include: { s -> Bool in return s.characters.count > 3 }) .merge(with: offlineSignal.distinct()) .combineLatest(with: viewModel.title.map { t -> Bool in return t != nil }).bind(to: refreshButton.reactive.isEnabled)

Slide 33

Slide 33 text

NO MORE 
 IMPERATIVE?

Slide 34

Slide 34 text

DESIGNING APIS • don't expose reactive, • support it

Slide 35

Slide 35 text

THANKS
 @vasarhelyia

Slide 36

Slide 36 text

RESOURCES https://github.com/ReactiveKit/Bond https://github.com/ReactiveX/RxSwift https://github.com/ReactiveCocoa/ReactiveCocoa https://github.com/mattgallagher/CwlSignal https://www.cocoawithlove.com/blog/reactive-programming-what-and-why.html https://www.youtube.com/watch?v=7AqXBuJOJkY https://speakerdeck.com/joshaber/better-code-for-a-better-world Photos from unsplash.com