Slide 1

Slide 1 text

for mobile ++ = Reactive Extensions Mobile@Scale | Tel Aviv, Israel | Nov 14th, 2018

Slide 2

Slide 2 text

About Me Shai Mishali @freak4pc iOS Tech Lead @ Gett Open Source = ❤ Won some hackathons Battlehack Tel Aviv 2014
 Battlehack World Finals 2014 Ford Dev Challenge 2015 iOS Team @ RW

Slide 3

Slide 3 text

Agenda • What is Rx & Why you’d want to use it? • Rx Building Blocks • Defining Behaviors with Streams • Differences between RxSwift and RxJava • Debunking some Myths • Where to go next? And of course … An absurd amount of Memes

Slide 4

Slide 4 text

What is rx?

Slide 5

Slide 5 text

What is Rx? “An API for asynchronous programming with observable streams” - reactivex.io

Slide 6

Slide 6 text

What is Rx?

Slide 7

Slide 7 text

Observers / Subscribers the observer pattern “A software design pattern in which an object (Observable) maintains a list of Observers and notifies them automatically of changes.” isReady
 Observable View 1
 Observer Some
 Manager
 Observer Activity
 Indicator Observer View 2 Observer

Slide 8

Slide 8 text

What is Rx? - Focusing on Data Flow and Defined Behavior to
 drive your application. - A new concept to most iOS developers, more popular in the Android community. - High learning curve - This lecture won’t make you an
 Rx expert. - Most likely will bend your brain a bit until it “clicks”. Be Patient !

Slide 9

Slide 9 text

Why use rx?

Slide 10

Slide 10 text

WHY USE RX? • Provides a unified API for dealing with asynchronous actions (e.g. Observable). • Provides a mechanism to Reactively handle and manipulate Values over Time. ⏳ • Focus on Writing Declarative and Expected Code that defines behaviour. Data is king. • The rise of Kotlin makes inter-team logic sharing/ discussion easier than ever. • Encourages good architecture.

Slide 11

Slide 11 text

multi-platform Moving between platforms is relatively seamless, since ReactiveX provides a standard implemented in many languages.
 
 Learn once, use anywhere RxSwift RxJava RxKotlin Rx.NET RxJS RxDart RxGo and many more …

Slide 12

Slide 12 text

Companies using Rx Rx is mature and has been in use by some of the biggest tech companies

Slide 13

Slide 13 text

REACTIVE let canMakePurchase = Observable .combineLatest(userBalance, productPrice) .map { $0 >= $1 } // Observable canMakePurchase ALWAYS reflects the latest state canMakePurchase doesn’t reflect the latest state var userBalance = 5 let productPrice = 10 let canMakePurchase = userBalance >= productPrice print(canMakePurchase) userBalance += 20 print(canMakePurchase) // false // STILL false!

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

Simple Easy

Slide 16

Slide 16 text

Rx Building Blocks

Slide 17

Slide 17 text

Observable Int Independent Values 1 52 1337 52 70000 -24 404 Observable Values over time 40 1 404 -24 1337

Slide 18

Slide 18 text

observable lifecycle An Observable (aka Stream) may emit any number of next(value) events next next next next next next next next error X next next next completed X next When it emits a single error or completed event, the sequence will terminate

Slide 19

Slide 19 text

everything is a stream

Slide 20

Slide 20 text

everything is a stream Any values/events over time can be modeled as an Observable Stream tap Taps on a button: tap tap tap tap tap tap tap Networking: Array of Results completed X Number of products in a shopping cart: 1 2 5 4 5 0

Slide 21

Slide 21 text

Observable Notifications
 Storage
 Delegates / Adapters Bindings
 ↔ UI
 Events
 Networking
 everything is a stream

Slide 22

Slide 22 text

subscribing The act of listening or observing events emitted by
 an Observable is called Subscribing.

Slide 23

Slide 23 text

subscribing let numbers = Observable.of(1, 4, -24, 400) numbers.subscribe( onNext: { value in print("Got next: \(value)") }, onError: { error in print("An error occurred: \(error)") }, onCompleted: { print("Completed") }) .disposed(by: disposeBag) val numbers = Observable .from(listOf(1, 4, -24, 400)) numbers.subscribeBy( onNext = { println("Got next: $it") }, onError = { println("Got error: $it") }, onComplete = { println("Completed") } )

Slide 24

Slide 24 text

subscribing let numbers = Observable.of(1, 4, -24, 400) numbers.subscribe( onNext: { value in print("Got next: \(value)") }, onError: { error in print("An error occurred: \(error)") }, onCompleted: { print("Completed") }) .disposed(by: disposeBag) val numbers = Observable .from(listOf(1, 4, -24, 400)) numbers.subscribeBy( onNext = { println("Got next: $it") }, onError = { println("Got error: $it") }, onComplete = { println("Completed") } )

Slide 25

Slide 25 text

subscribing let numbers = Observable.of(1, 4, -24, 400) numbers.subscribe( onNext: { value in print("Got next: \(value)") }, onError: { error in print("An error occurred: \(error)") }, onCompleted: { print("Completed") }) .disposed(by: disposeBag) val numbers = Observable .from(listOf(1, 4, -24, 400)) numbers.subscribeBy( onNext = { println("Got next: $it") }, onError = { println("Got error: $it") }, onComplete = { println("Completed") } )

Slide 26

Slide 26 text

subscribing let numbers = Observable.of(1, 4, -24, 400) numbers.subscribe( onNext: { value in print("Got next: \(value)") }, onError: { error in print("An error occurred: \(error)") }, onCompleted: { print("Completed") }) .disposed(by: disposeBag) val numbers = Observable .from(listOf(1, 4, -24, 400)) numbers.subscribeBy( onNext = { println("Got next: $it") }, onError = { println("Got error: $it") }, onComplete = { println("Completed") } )

Slide 27

Slide 27 text

subscribing let numbers = Observable.of(1, 4, -24, 400) numbers.subscribe( onNext: { value in print("Got next: \(value)") }, onError: { error in print("An error occurred: \(error)") }, onCompleted: { print("Completed") }) .disposed(by: disposeBag) val numbers = Observable .from(listOf(1, 4, -24, 400)) numbers.subscribeBy( onNext = { println("Got next: $it") }, onError = { println("Got error: $it") }, onComplete = { println("Completed") } )

Slide 28

Slide 28 text

subscribing let numbers = Observable.of(1, 4, -24, 400) numbers.subscribe( onNext: { value in print("Got next: \(value)") }, onError: { error in print("An error occurred: \(error)") }, onCompleted: { print("Completed") }) .disposed(by: disposeBag) val numbers = Observable .from(listOf(1, 4, -24, 400)) numbers.subscribeBy( onNext = { println("Got next: $it") }, onError = { println("Got error: $it") }, onComplete = { println("Completed") } )

Slide 29

Slide 29 text

let numbers = Observable.of(1, 4, -24, 400) numbers.subscribe( onNext: { value in print("Got next: \(value)") }, onError: { error in print("An error occurred: \(error)") }, onCompleted: { print("Completed") }) .disposed(by: disposeBag) val numbers = Observable .from(listOf(1, 4, -24, 400)) numbers.subscribeBy( onNext = { println("Got next: $it") }, onError = { println("Got error: $it") }, onComplete = { println("Completed") } ) subscribing Got next: 1 Got next: 4 Got next: -24 Got next: 400 Console output: Completed

Slide 30

Slide 30 text

subscribing

Slide 31

Slide 31 text

Declaring Behaviors One of the most powerful aspects of Rx is composing, manipulating and transforming Observables into other Observables in a way that defines Behavior (e.g. Declarative) Button tap Network Request Transformed to … Transformed to… Array of Models Driving … UITableView
 RecyclerView Array All People Array Favorite people Filtered into … Driving … UITableView
 RecyclerView username String password String isValid Bool Button isEnabled Button Title Composed into … Button Title Driving … Driving … Transformed to

Slide 32

Slide 32 text

Declaring Behaviors One of the most powerful aspects of Rx is composing, manipulating and transforming Observables into other Observables in a way that defines Behavior (e.g. Declarative) Button tap Network Request Transformed to … Transformed to… Array of Models Driving … UITableView RecyclerView Array All People Array Favorite people Filtered into … Driving … UITableView RecyclerView username String password String isValid Bool Button isEnabled Button Title Composed into … Button Title Driving … Driving … Transformed to

Slide 33

Slide 33 text

Operators

Slide 34

Slide 34 text

Operators • Lets you manipulate the Observable stream. • Most operators act the same between platforms, but some languages have behaviour specific to them. • Most of them are Chainable (operator works on an Observable and returns an Observable). • Many “extra” operators exist in the community. • You can quite easily make your own.

Slide 35

Slide 35 text

Operators Transform Filter Create Combine Error Handling Utilities

Slide 36

Slide 36 text

Defining Behaviors

Slide 37

Slide 37 text

Defining Behaviors // Observable store = latestLocation .flatMapLatest { storeService.getNearby(coordinate: $0) .retry(3) } // Observable title = store.map { “Ordering from {$0.name}" }

Slide 38

Slide 38 text

Defining Behaviors // Observable store = latestLocation .throttle(0.3) .flatMapLatest { storeService.getNearby(coordinate: $0) .retry(3) } // Observable title = store.map { “Ordering from {$0.name}" }

Slide 39

Slide 39 text

Defining Behaviors currentLocation store title Navigation Title

Slide 40

Slide 40 text

Defining Behaviors // Observable<[MenuItem]> menu = store .flatMapLatest { menuService.getMenu(for: $0.id) .retry(3) } // Observable subtitle = menu.map { "Store has {$0.count} items" }

Slide 41

Slide 41 text

Defining Behaviors currentLocation store menu subtitle title Navigation Title Navigation Title & Subtitle

Slide 42

Slide 42 text

Defining Behaviors // store - Observable // menu - Observable<[MenuItem]> // Observable canMakeOrder = Observable .combineLatest(store, menu) .map { $0.isOpen && !$1.isEmpty } // Observable buttonTitle = canMakeOrder .map { $0 ? "Add some items!” : “Store unavailable" }

Slide 43

Slide 43 text

Defining Behaviors currentLocation store menu subtitle canMakeOrder buttonTitle title Navigation Title & Subtitle Button Title & Enabled state

Slide 44

Slide 44 text

Defining Behaviors // store - Observable // Observable<([MenuItem], Distance)> menuAndDistance = store .flatMapLatest { Observable.zip( menuService.getMenu(for: $0.id), etaService.getETA(to: $0.location) ) } // Observable subtitle = menuAndDistance .map { "Store has {$0.menu.count} “ + “items and is {$0.distance)m away" }

Slide 45

Slide 45 text

Defining Behaviors currentLocation store menu subtitle canMakeOrder buttonTitle menuAndDistance title Button Title & Enabled state Navigation Title & Subtitle

Slide 46

Slide 46 text

Defining Behaviors // Observable store = latestLocation .flatMapLatest { storeService.getNearby(coordinate: $0) .retry(3) }

Slide 47

Slide 47 text

Defining Behaviors // Observable store = Observable.merge( locationChanged, tappedRefresh ) .withLatestFrom(latestLocation) .flatMapLatest { storeService.getNearby(coordinate: $0) .retry(3)
 }

Slide 48

Slide 48 text

Defining Behaviors // Observable store = Observable.merge( locationChanged, tappedRefresh, becameReachable ) .withLatestFrom(latestLocation) .flatMapLatest { storeService.getNearby(coordinate: $0) .retry(3)
 }

Slide 49

Slide 49 text

Defining Behaviors currentLocation store subtitle canMakeOrder buttonTitle menu tappedRefresh becameReacahable menuAndDistance Button Title & Enabled state title Navigation Title & Subtitle

Slide 50

Slide 50 text

Defining Behaviors currentLocation store subtitle canMakeOrder buttonTitle menu tappedRefresh becameReacahable menuAndDistance Button Title & Enabled state title Navigation Title & Subtitle

Slide 51

Slide 51 text

Error Handling Operators Transform Filter Create Combine Utilities A full list of operators is available at http://reactivex.io/documentation/operators.html create just of from deferred map flatMap flatMapLatest scan filter throttle debounce distinctUntilChanged skip take first last observeOn subscribeOn delay do materialize dematerialize retry retryWhen catchError catchErrorJustReturn combineLatest merge concat startWith zip

Slide 52

Slide 52 text

Operators Ok - so I know about Observables and how to use some Operators, but …

Slide 53

Slide 53 text

Rx + Mobile UI

Slide 54

Slide 54 text

Rx + Mobile UI ??? RxSwift RxJava Neutral implementation Based on ReactiveX iOS & macOS, tvOS, watchOS Android Now that we have our streams, how do we actually “feed” values from them into our App’s UI Elements, and the other way around ?

Slide 55

Slide 55 text

Rx + Mobile UI Streams of UI components RxCocoa (part of RxSwift) lets you “subscribe” to events/ properties on most standard UI components as Observable streams under the rx namespace, as well as most delegates. Easily customizable. RxBinding (by Jake Wharton, not part of RxJava) lets you “subscribe” to a similar set of most basic UI components. Custom components aren’t entirely trivial. button.rx.tap textField.rx.text slider.rx.value collection.rx.itemSelected datePicker.rx.date RxView.clicks(button) RxView.focusChanges(editText) RxTextView.textChanges(editText) RxSeekBar.userChanges

Slide 56

Slide 56 text

Rx + Mobile UI Feeding streams into UI components RxCocoa provides a special unit called a Binder that lets you bind streams directly into UI components. You can easily create your own bindings for custom components. Bindings aren’t as popular or trivial and are used mainly by more “hardcore” Rx people. Standard use cases simply use the standard subscribe for the stream. textStream.bind(to: lblTitle.rx.text) isFormValid.bind(to: btnSubmit.rx.isEnabled) buttonTitle.bind(to: button.rx.title()) yourStream.bind(to: customView.rx.yourProperty) textStream.subscribe( { textView.text = $it }, { Log.e("MainActivity", "$it") } )

Slide 57

Slide 57 text

Operators

Slide 58

Slide 58 text

Debunking some Myths

Slide 59

Slide 59 text

There are 2 main myths ✌

Slide 60

Slide 60 text

You have to go
 “All or Nothing”

Slide 61

Slide 61 text

It’s insanely hard! RxSwift: Use .debug() operator RxJava: Log in doOnEach() or use a breakpoint Learning Curve is High, but once you “Think Rx”, it’s hard to go back :-) RxSwift: Use a DisposeBag
 RxJava: JVM Garbage Collection / CompositeDisposable Ob ser ver Ob ser ver Obser Obser ver 2 DisposeBag

Slide 62

Slide 62 text

Next Steps

Slide 63

Slide 63 text

Awesome Job! You made it !

Slide 64

Slide 64 text

Want to learn more? Official RxSwift & RxJava Documentation: http://github.com/ReactiveX/RxSwift https://github.com/ReactiveX/RxJava/tree/2.x/docs ReactiveX Documentation: http://reactivex.io/documentation/observable.html RxMarbles: http://rxmarbles.com/ RxSwift: Reactive Programming with Swift (RayWenderlich): Reactive Programming with RxJava (O’Reilly): https://store.raywenderlich.com/products/rxswift-reactive-programming-with-swift https://www.oreilly.com/library/view/reactive-programming-with/9781491931646/

Slide 65

Slide 65 text

Book Raffle!! We’re giving away RayWenderlich’s RxSwift & Kotlin Apprentice books! https://bit.ly/rxfreebook

Slide 66

Slide 66 text

Thank you! Shai Mishali freak4pc Questions?