Upgrade to Pro — share decks privately, control downloads, hide ads and more …

RxSwift: Deep Cuts

RxSwift: Deep Cuts

Krzysztof Siejkowski

October 21, 2017
Tweet

More Decks by Krzysztof Siejkowski

Other Decks in Programming

Transcript

  1. dataProvider.refreshData() .subscribe( onNext: { [weak self] in self!?.update(with: $0) },

    onError: { [weak self] in if let error = $0 as? ReasonableError { self!?.showUserMessage(with: error.reason) } } ) .disposed(by: disposeBag)
  2. dataProvider.refreshData() .subscribe( onNext: { [weak self] in self!?.update(with: $0) },

    onError: { [weak self] in if let error = $0 as? ReasonableError { self!?.showUserMessage(with: error.reason) } } ) .disposed(by: disposeBag)
  3. dataProvider.refreshData() .subscribe( onNext: { [weak self] in self!?.update(with: $0) },

    onError: { [weak self] in if let error = $0 as? ReasonableError { self!?.showUserMessage(with: error.reason) } } ) .disposed(by: disposeBag)
  4. dataProvider.refreshData() .subscribe( onNext: { [weak self] in self!?.update(with: $0) },

    onError: { [weak self] in if let error = $0 as? ReasonableError { self!?.showUserMessage(with: error.reason) } } ) .disposed(by: disposeBag)
  5. dataProvider.refreshData() .subscribe( onNext: { [weak self] in self!?.update(with: $0) },

    onError: { [weak self] in if let error = $0 as? ReasonableError { self!?.showUserMessage(with: error.reason) } } ) .disposed(by: disposeBag)
  6. dataProvider.refreshData() .subscribe( onNext: { [weak self] in self!?.update(with: $0) },

    onError: { [weak self] in if let error = $0 as? ReasonableError { self!?.showUserMessage(with: error.reason) } } ) .disposed(by: disposeBag)
  7. Observable .just(42) .filter { $0 > 30 } .map {

    “\($0)” } Just Filter Map
  8. Observable .just(42) .filter { $0 > 30 } .map {

    “\($0)” } .distinctUntilChanged { $0 !== $1 } Just Filter Map Distinct UntilChanged
  9. let observable: Observable<String> = Observable .just(42) .filter { $0 >

    30 } .map { “\($0)” } .distinctUntilChanged { $0 !== $1 } Just Filter Map observable observable
  10. environment Observable .just(42) .filter { $0 > 30 } .map

    { “\($0)” } .distinctUntilChanged { $0 !== $1 } Just Filter Map Distinct UntilChanged filter closure compare closure map closure
  11. Observable .just(42) .filter { $0 > 30 } .map {

    “\($0)” } .distinctUntilChanged { $0 !== $1 } .subscribe { print($0) } Just Filter Map Distinct UntilChanged filter closure compare closure map closure Just Sink Filter Sink Map Sink DUC Sink
  12. Observable .just(42) .filter { $0 > 30 } .map {

    “\($0)” } .distinctUntilChanged { $0 !== $1 } .subscribe { print($0) } Just Filter Map Distinct UntilChanged filter closure compare closure map closure Just Sink Filter Sink Map Sink DUC Sink
  13. Observable .just(42) .filter { $0 > 30 } .map {

    “\($0)” } .distinctUntilChanged { $0 !== $1 } .subscribe { print($0) } Just Filter Map Distinct UntilChanged filter closure compare closure map closure Just Sink Filter Sink Map Sink DUC Sink Observer Observer
  14. filter closure compare closure map closure Just Sink Filter Sink

    Map Sink DUC Sink Observer Just Sink Disposer Filter Sink Disposer Map Sink Disposer DUC Sink Disposer Observable .just(42) .filter { $0 > 30 } .map { “\($0)” } .distinctUntilChanged { $0 !== $1 } .subscribe { print($0) }
  15. reference cycles filter closure compare closure map closure Just Sink

    Filter Sink Map Sink DUC Sink Observer Just Sink Disposer Filter Sink Disposer Map Sink Disposer DUC Sink Disposer
  16. filter closure compare closure map closure Just Sink Filter Sink

    Map Sink DUC Sink Observer Just Sink Disposer Filter Sink Disposer Map Sink Disposer disposable let disposable: Disposable = Observable .just(42) .filter { $0 > 30 } .map { “\($0)” } .distinctUntilChanged { $0 !== $1 } .subscribe { print($0) }
  17. disposable .dispose() filter closure compare closure map closure Just Sink

    Filter Sink Map Sink DUC Sink Observer Just Sink Disposer Filter Sink Disposer Map Sink Disposer disposable
  18. filter closure compare closure map closure Just Sink Filter Sink

    Map Sink DUC Sink Observer Just Sink Disposer Filter Sink Disposer Map Sink Disposer disposable observe closure let disposable = Observable .just(42) .filter { $0 > 30 } .map { “\($0)” } .distinctUntilChanged { $0 !== $1 } .subscribe { print($0) }
  19. environment let disposable = Observable .just(42) .filter { $0 >

    30 } .map { “\($0)” } .distinctUntilChanged { $0 !== $1 } .subscribe { print($0) } filter closure compare closure map closure Just Sink Filter Sink Map Sink DUC Sink Observer Just Sink Disposer Filter Sink Disposer Map Sink Disposer disposable observe closure
  20. observable .map { [weak self] in self!?.transform($0) } .subscribe {

    [weak self] in self!?.react(to: $0) } observable .map { [unowned self] in self.transform($0) } .subscribe { [unowned self] in self.react(to: $0) } .disposed( by: self.disposeBag )
  21. !// instance method func foo(_ bar: Int) !-> Int !//

    instance scope Observable.just(42) .map(foo) !// instance method func foo(_ bar: Int) !-> Int !// instance scope Observable.just(42) .map { self.foo($0) }
  22. dataProvider.refreshData() .subscribe( onNext: { [weak self] in self!?.update(with: $0) },

    onError: { [weak self] in if let error = $0 as? ReasonableError { self!?.showUserMessage(with: error.reason) } } ) .disposed(by: disposeBag)
  23. dataProvider.refreshData() .subscribe( onNext: { [unowned self] in self.update(with: $0) },

    onError: { [unowned self] in if let error = $0 as? ReasonableError { self.showUserMessage(with: error.reason) } } ) .disposed(by: disposeBag)
  24. dataProvider.refreshData() .subscribe( onNext: { [unowned self] in self.update(with: $0) },

    onError: { [unowned self] in if let error = $0 as? ReasonableError { self.showUserMessage(with: error.reason) } } ) .disposed(by: disposeBag)
  25. MainScheduler let mainQueue = DispatchQueue.main !// simplified essence of schedule

    method if DispatchQueue.isMain { action(state) } else { mainQueue.async { action(state) } }
  26. SerialDispatchQueueScheduler !// internal serial dispatch queue of given properties let

    queue = DispatchQueue.global(qos: qos.qosClass) !// simplified essence of schedule method queue.async { action(state) }
  27. OperationQueueScheduler !// operation queue provided by client in the initializer

    let operationQueue: OperationQueue !// simplified essence of schedule method operationQueue.addOperation( BlockOperation { action(state)) } )
  28. Also in schedulers • QOS • serial / concurrent •

    immediate / delayed • driven by client
  29. Observable .just(42) .filter { $0 > 33 } .map {

    "\($0)" } .subscribe { print($0) } .disposed(by: disposeBag) Subscription thread
  30. Observable .just(42) .observeOn(greenScheduler) .filter { $0 > 33 } .map

    { "\($0)" } .subscribe { print($0) } .disposed(by: disposeBag) Subscription thread Green scheduler
  31. Observable .just(42) .observeOn(greenScheduler) .filter { $0 > 33 } .observeOn(redScheduler)

    .map { "\($0)" } .observeOn(greenScheduler) .subscribe { print($0) } .disposed(by: disposeBag) Subscription thread Red scheduler Green scheduler Green scheduler
  32. Observable .just(42) .observeOn(greenScheduler) .filter { $0 > 33 } .observeOn(redScheduler)

    .subscribeOn(blueScheduler) .map { "\($0)" } .observeOn(greenScheduler) .subscribe { print($0) } .disposed(by: disposeBag) Blue scheduler Red scheduler Green scheduler Green scheduler
  33. Observable .just(42) .observeOn(greenScheduler) .filter { $0 > 33 } .subscribeOn(blueScheduler)

    .observeOn(redScheduler) .subscribeOn(redScheduler) .map { "\($0)" } .observeOn(greenScheduler) .subscribeOn(greenScheduler) .subscribe { print($0) } .disposed(by: disposeBag) Blue scheduler Red scheduler Green scheduler Green scheduler
  34. Observable .just( 42, scheduler: blueScheduler ) .observeOn(greenScheduler) .filter { $0

    > 33 } .observeOn(redScheduler) .subscribeOn(redScheduler) .map { "\($0)" } .observeOn(greenScheduler) .subscribe { print($0) } .disposed(by: disposeBag) Blue scheduler Red scheduler Green scheduler Green scheduler
  35. Schedule-using for generation !// Scheduler to send elements on. .fromScheduled([1,

    2, 3], greenScheduler) !// Scheduler to run the producer loop on. .repeatElement(1, blueScheduler) !// Scheduler to run the timer on. .interval(1, redScheduler)
  36. Schedule-using for internal work !// Scheduler to run the throttle

    timers on. .throttle(1, blueScheduler) !// Scheduler to run the subscription delay timer on. .delay(1, greenScheduler) !// Scheduler to run buffering timers on. .buffer(timeSpan: 1, count: 3, scheduler: redScheduler)
  37. Observable<Int> .merge([ Observable<Int>.interval(3, redScheduler), Observable<Int>.interval(5, greenScheduler), ]) .subscribe { [unowned

    self] in !// sometimes red, sometimes green self.work(with: $0) } .disposed(by: disposeBag)
  38. dataProvider.refreshData() .observeOn(MainScheduler.instance) .subscribe( onNext: { [unowned self] in self.update(with: $0)

    }, onError: { [unowned self] in if let error = $0 as? ReasonableError { self.showUserMessage(with: error.reason) } } ) .disposed(by: disposeBag)
  39. dataProvider.refreshData() .observeOn(MainScheduler.instance) .subscribe( onNext: { [unowned self] in self.update(with: $0)

    }, onError: { [unowned self] in if let error = $0 as? ReasonableError { self.showUserMessage(with: error.reason) } } ) .disposed(by: disposeBag)
  40. Finishing !// you may ignore disposable (though I recommend not

    to!) _ = observable .subscribe(onNext: { [weak self] in self!?.work(on: $0) })
  41. Not finishing let disposable = observable .subscribe(onNext: { [weak self]

    in self!?.work(on: $0) }) !// ensure subscription disposing disposable.dispose() disposable.disposed(by: disposeBag)
  42. One-off let serial = SerialDisposable() !// call each time you

    want the fresh data func fetchFreshData() { serial.disposable = observable .subscribe(onNext: { [unowned self] in self.work(on: $0) }) }
  43. Updating let disposeBag = DisposeBag() !// call only once in

    the object lifetime func listenForFreshData() { observable .subscribe(onNext: { [unowned self] in self.work(on: $0) }) .disposed(by: disposeBag) }
  44. Immediately & synchronously !// if not ready to handle data

    at the `subscribe` time dataProvider .data() .skip(1) .subscribe(onNext: { [unowned self] in self.work(on: $0) }) .disposed(by: disposeBag)
  45. After some time & asynchronously !// provide separate method for

    fetching initial data let initialData = dataProvider.getInitialData() dataProvider .dataUpdates() .subscribe(onNext: { [unowned self] in self.work(on: $0) }) .disposed(by: disposeBag)
  46. Not caching let observable = dataProvider .fetchHugeAmountOfDataFromNetwork() !// costly network

    request with fresh data observable.subscribe() !// costly network request with fresh data observable.subscribe()
  47. Caching let observable = dataProvider .fetchHugeAmountOfDataFromNetwork() .shareReplay(1) !// costly network

    request with fresh data observable.subscribe() !// no network refresh but also old data observable.subscribe()
  48. !/* Returns an Observable that emits at most three times,

    starting with the first event emitted immediately and synchronously upon subscription. Times of other two events are not guaranteed. May not complete, but never errors out. Doesn’t cache any data. !*/ public func thirdTimeLucky() !-> Observable<Data>
  49. final class DataProvider { private let proxySubject = PublishSubject<Data>() var

    data: Observable<Data> { return proxySubject.asObservable() } func refreshData() !-> Observable<Void> { return networkService .requestData() .do(onNext: { proxySubject.onNext($0) } .map { _ in } }
  50. dataProvider.refreshData() .observeOn(MainScheduler.instance) .subscribe( onNext: { [unowned self] in self.update(with: $0)

    }, onError: { [unowned self] in if let error = $0 as? ReasonableError { self.showUserMessage(with: error.reason) } } ) .disposed(by: disposeBag)