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

Everyday Reactive (try! Swift Tokyo '17)

Everyday Reactive (try! Swift Tokyo '17)

This is my talk from try! Swift Tokyo exploring tips and tricks for determining when reactive programming can be a potent tool, as well as scenarios to avoid that might threaten code quality and performance. The talk's focus is on concepts in reactive programming, the code shows off different Swift reactive implementations.

https://www.tryswift.co/tokyo/

Agnes Vasarhelyi

March 09, 2017
Tweet

More Decks by Agnes Vasarhelyi

Other Decks in Programming

Transcript

  1. "Reactive programming manages asynchronous data flows between sources of data

    and components that need to react to that data." MATT GALLAGHER, COCOAWITHLOVE.COM
  2. let (signal, observer) = Signal<String, NoError>.pipe() signal.observeValues { animal in

    print( "value: \(animal)") } observer.sendNext(value: "") observer.sendNext(value: "") > value: > value: ReactiveSwift (RAC)
  3. var loading: Bool var userLoggedIn: Bool var didShowAlert: Bool var

    loading = reactive(userLoggedIn) && reactive(didShowAlert) 23 STATE 22 STATE
  4. let userLoggedIn = PublishSubject<Bool>() let didLoadContent = PublishSubject<Bool>() 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
  5. 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
  6. func logAnimals() { let animal = MutableProperty<String>("") 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)
  7. 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
  8. viewModel.title.map { n -> Bool in return n != nil

    }.bind(to: refreshButton.reactive.isEnabled) Bond
  9. 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
  10. 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 =
  11. ... .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)