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

ca.swift_2.pdf

Kyohei Ito
March 01, 2017
1.2k

 ca.swift_2.pdf

Kyohei Ito

March 01, 2017
Tweet

Transcript

  1. RxSwift Operators Tips
    2017/03/1 CA.swift

    View full-size slide

  2. About Me
    ҏ౻ɹګฏ
    Github : KyoheiG3
    Twitter : @KyoheiG3

    View full-size slide

  3. ͖Ε͍ͳ઒ͷྲྀΕΛकΔͨΊͷ੍໿ͦͷᶃ
    ઒Λ෼அ͠ͳ͍

    View full-size slide

  4. ͖Ε͍ͳ઒ͷྲྀΕΛकΔͨΊͷ੍໿ͦͷᶃ
    → DisposeBagΛෳ਺ʹ෼͚ͳ͍

    View full-size slide

  5. flatMap
    Observable͔Βૹ৴͞ΕͨΞΠςϜΛObservablesʹม׵͠ɺ
    ͦͷޙͦΕΒ͔Βૹ৴͞ΕΔΞΠςϜΛ̍ͭͷObservable΁ม
    ׵͢Δɻ

    View full-size slide

  6. flatMap
    ઒͔Β઒΁ɺྲྀΕΛͭͳ͙

    View full-size slide

  7. Bad Stream
    botton.rx.tap
    .subscribe(onNext: {
    URLSession.shared.rx.json(request: request)
    .subscribe(onNext: { ... })
    .addDisposableTo(disposeBag)
    })
    .addDisposableTo(disposeBag)

    View full-size slide

  8. Good Stream
    botton.rx.tap
    .flatMap {
    URLSession.shared.rx.json(request: request)
    }
    .subscribe(onNext: { ... })
    .addDisposableTo(disposeBag)

    View full-size slide

  9. flatMapͷಛ௃
    લճͷΠϕϯτ͕ऴ͍ྃͯ͠ͳͯ͘΋ΞΠςϜ͕ετϦʔϜʹྲྀ
    ΕΔͷͰɺಉ͡ॲཧ͕ෳ਺ճߦΘΕΔՄೳੑ͕͋Δɻ

    View full-size slide

  10. ඇಉظॲཧͰ΍Γ͍ͨ͜ͱ
    ௨৴ͳͲͷඇಉظॲཧ͸ɺॲཧத͸ετϦʔϜΛྲྀ͞ͳ͍ɺ·
    ͨ͸࠷৽ͷετϦʔϜ͚ͩΛྲྀ͍ͨ͠ɻ

    View full-size slide

  11. flatMapLatest

    View full-size slide

  12. flatMapLatest
    ઒ͷྲྀΕΛஅͪ੾ͬͯɺ࣍ͷ઒΁ͱྲྀΕΛͭͳ͙

    View full-size slide

  13. Bad Stream
    botton.rx.tap
    .subscribe(onNext: {
    requestDisposeBag = DisposeBag()
    URLSession.shared.rx.json(request: request)
    .subscribe(onNext: { ... })
    .addDisposableTo(requestDisposeBag)
    })
    .addDisposableTo(disposeBag)

    View full-size slide

  14. Good Stream
    botton.rx.tap
    .flatMapLatest {
    URLSession.shared.rx.json(request: request)
    }
    .subscribe(onNext: { ... })
    .addDisposableTo(disposeBag)

    View full-size slide

  15. flatMapLatestͷಛ௃
    ৽͍͠Πϕϯτ͕ىͬͨ͜ΒલͷΠϕϯτΛഁغͯ࣍͠ͷΠϕϯ
    τΛߦ͏ͷͰɺ୯Ұͷॲཧ͔͠ߦΘΕͳ͍ɻ
    Timer΍IntervalͳͲͷඇಉظॲཧ΋ɺflatMapLatestͱ૬ੑ͕
    Α͍ɻ

    View full-size slide

  16. Timer Stream
    botton.rx.tap
    .flatMapLatest {
    Observable.timer(1, scheduler: scheduler)
    }
    .subscribe(onNext: { ... })
    .addDisposableTo(disposeBag)

    View full-size slide

  17. debounceͱॲཧ͕Α͘ࣅ͍ͯΔ

    View full-size slide

  18. Debounce
    botton.rx.tap
    .debounce(1, scheduler: scheduler)
    .subscribe(onNext: { ... })
    .addDisposableTo(disposeBag)

    View full-size slide

  19. DebounceͱTimer Streamͷҧ͍
    ετϦʔϜʹྲྀΕ͖ͯͨ஋Λ΋ͱʹintervalΛม͑Δ͜ͱ͕Ͱ
    ͖Δɻ

    View full-size slide

  20. έʔεͦͷᶃ
    ΞΠςϜΛड͚औ͔ͬͯΒɺҰఆ࣌ؒޙʹΞΠςϜΛετϦʔϜ
    ʹྲྀ͍ͨ͠ɻ஗Ԇ࣌ؒ͸ΞΠςϜͷ಺༰ʹΑͬͯ൑அ͢Δɻ

    View full-size slide

  21. {
    "num": 10,
    "title": "Timer Stream"
    }

    View full-size slide

  22. Timer Stream
    botton.rx.tap
    .flatMapLatest {
    URLSession.shared.rx.json(request: request)
    }
    .flatMapLatest { json -> Observable in
    Observable.timer(json["num"] as! Int, scheduler: scheduler)
    .map { _ in json }
    }
    .subscribe(onNext: { ... })
    .addDisposableTo(disposeBag)

    View full-size slide

  23. έʔεͦͷᶄ
    ΞΠςϜΛड͚औͬͨΒετϦʔϜʹྲྀ͕͢ɺҰఆ࣌ؒޙʹnil
    ΛετϦʔϜʹྲྀ͍ͨ͠ɻ஗Ԇ࣌ؒ͸ΞΠςϜͷ಺༰ʹΑͬͯ
    ൑அ͢Δɻ

    View full-size slide

  24. έʔεͦͷᶄ
    startWithΛ࢖͏

    View full-size slide

  25. Timer Stream
    botton.rx.tap
    .flatMapLatest {
    URLSession.shared.rx.json(request: request)
    }
    .flatMapLatest { json -> Observable in
    Observable.timer(json["num"] as! Int, scheduler: scheduler)
    .map { _ in nil }
    .startWith(json)
    }
    .subscribe(onNext: { ... })
    .addDisposableTo(disposeBag)

    View full-size slide

  26. flatMapFirst

    View full-size slide

  27. flatMapFirst
    ઒ͷྲྀΕ͕ࢭ·Δ·Ͱɺ࣍ͷ઒΁͸ͭͳ͕ͳ͍

    View full-size slide

  28. Bad Stream
    var requesting = false
    botton.rx.tap
    .subscribe(onNext: {
    if requesting { return }
    requesting = true
    requestDisposeBag = DisposeBag()
    URLSession.shared.rx.json(request: request)
    .subscribe(onNext: {
    requesting = false
    })
    .addDisposableTo(requestDisposeBag)
    })
    .addDisposableTo(disposeBag)

    View full-size slide

  29. Good Stream
    botton.rx.tap
    .flatMapFirst {
    URLSession.shared.rx.json(request: request)
    }
    .subscribe(onNext: { ... })
    .addDisposableTo(disposeBag)

    View full-size slide

  30. flatMapFirstͷಛ௃
    ࠷ॳʹૹ৴͞ΕͨΞΠςϜͷॲཧ͕׬ྃ͢Δ·Ͱ͸ɺͦͷޙʹ
    ૹΒΕͨΞΠςϜΛ఻ൖ͠ͳ͍ͷͰɺ୯Ұͷॲཧ͔͠ߦΘΕͳ
    ͍ɻ

    View full-size slide

  31. Timer Stream
    botton.rx.tap
    .flatMapFirst {
    Observable.timer(1, scheduler: scheduler)
    }
    .subscribe(onNext: { ... })
    .addDisposableTo(disposeBag)

    View full-size slide

  32. throttleͱॲཧ͕Α͘ࣅ͍ͯΔ

    View full-size slide

  33. Throttle
    botton.rx.tap
    .throttle(1, scheduler: scheduler)
    .subscribe(onNext: { ... })
    .addDisposableTo(disposeBag)

    View full-size slide

  34. Throttleͷ஫ҙ఺
    throttle͸ετϦʔϜ1ൃ໨ͷΞΠςϜ͕ྲྀΕͯ͘ΔͬΆ͍ɻ
    ੲ͸ྲྀΕͯ͜ͳ͔ͬͨͷͰɺ΋͔ͨ͠͠ΒόʔδϣϯʹΑͬͯ
    มΘΔ͔΋ɻ

    View full-size slide

  35. ͖Ε͍ͳ઒ͷྲྀΕΛकΔͨΊͷ੍໿ͦͷᶄ
    ઒ʹ΋ͷΛ౤͛ೖΕͳ͍

    View full-size slide

  36. ͖Ε͍ͳ઒ͷྲྀΕΛकΔͨΊͷ੍໿ͦͷᶄ
    → ΫϩʔδϟͰselfΛࢀরͤ͞ͳ͍

    View full-size slide

  37. selfΛࢀরͤ͞ͳ͍ํ๏
    ෳ਺ͷετϦʔϜΛ߹੒ɺ͋Δ͍͸ঢ়ଶΛ஌Δඞཁ͕͋Δɻ
    RxͷoperatorsҰཡͳͲΛ֬ೝͯ͠Έͯɺ(x, y)Έ͍ͨʹ2ͭͷ
    ஋Λࢀর͍ͯ͠ΔΑ͏ͳoperator͸߹੒νϟϯεɻ
    ׬શʹࢀর͠ͳ͍ͷ͸೉͍͠ͷͰɺͰ͖ΔݶΓͰ΍ͬͯΈΔɻ

    View full-size slide

  38. withLatestFrom

    View full-size slide

  39. withLatestFrom
    ͋ΔετϦʔϜʹରͯ͠ɺผͷετϦʔϜͷ࠷৽ͷΞΠςϜΛ߹
    ੒͢Δɻ

    View full-size slide

  40. Bad Stream
    let other = Variable(0)
    botton.rx.tap
    .subscribe(onNext: { [weak self] in
    self?.other.asObservable()
    .subscribe(onNext: { ... })
    .addDisposableTo(disposeBag)
    })
    .addDisposableTo(disposeBag)

    View full-size slide

  41. Self Reference
    let other = Variable(0)
    botton.rx.tap
    .subscribe(onNext: { [weak self] in
    print(self?.other.value)
    })
    .addDisposableTo(disposeBag)

    View full-size slide

  42. Good Stream
    let other = Variable(0)
    botton.rx.tap
    .withLatestFrom(other.asObservable())
    .subscribe(onNext: { ... })
    .addDisposableTo(disposeBag)

    View full-size slide

  43. withLatestFromͷಛ௃
    subscribeޙʹετϦʔϜʹྲྀΕͨ࠷৽ͷΞΠςϜͰ͋Ε͹ɺ
    VariableͷΑ͏ʹ஋Λอ͍࣋ͯ͠ͳͯ͘΋͍֮͑ͯͯ͘ΕΔͷ
    Ͱ߹੒͢Δ͜ͱ͕Ͱ͖Δɻ

    View full-size slide

  44. Good Stream
    let other = PublishSubject()
    botton.rx.tap
    .withLatestFrom(other)
    .subscribe(onNext: { ... })
    .addDisposableTo(disposeBag)

    View full-size slide

  45. scan
    Observable͔Βૹ৴͞ΕΔΞΠςϜʹ࿈ଓͯؔ͠਺Λద༻͢
    Δɻ

    View full-size slide

  46. Bad Stream
    let some = Variable(0)
    botton.rx.tap
    .flatMapLatest {
    URLSession.shared.rx.json(request: request)
    }
    .map { [weak self] json in
    let num = json["num"] as! Int
    if let value = self?.some.value {
    let new = value + num
    self?.some.value = new
    return new
    }
    return 0
    }
    .subscribe(onNext: { ... })
    .addDisposableTo(disposeBag)

    View full-size slide

  47. Good Stream
    botton.rx.tap
    .flatMapLatest {
    URLSession.shared.rx.json(request: request)
    }
    .map { json in json["num"] as! Int }
    .scan(0) { some, new in
    some + new
    }
    .subscribe(onNext: { ... })
    .addDisposableTo(disposeBag)

    View full-size slide

  48. scanͷಛ௃
    scanΛߦ͏͜ͱͰɺ͋ΔετϦʔϜʹରͯ͠ผͷΞΠςϜΛྲྀ
    ͢͜ͱ͕Ͱ͖Δɻ
    ετϦʔϜʹྲྀͨ͠ΞΠςϜ͸อ࣋͞Ε͍ͯΔͷͰɺ࣍ճετ
    ϦʔϜʹΞΠςϜ͕ྲྀΕ͖ͯͨࡍʹɺอ͍࣋ͯ͠ΔΞΠςϜͱ
    ྲྀΕ͖ͯͨΞΠςϜͷ྆ํΛಘΔ͜ͱ͕Մೳɻ

    View full-size slide

  49. scanͷಛ௃
    ৚݅ʹ߹Θͳ͚Ε͹ಉҰͷΞΠςϜΛྲྀ͠ଓ͚ͯɺ
    distinctUntilChangedΛ࣮ߦͯ͠ॲཧΛল͘͜ͱ΋Ͱ͖Δɻ

    View full-size slide

  50. Good Stream
    botton.rx.tap
    .flatMapLatest {
    URLSession.shared.rx.json(request: request)
    }
    .map { json in json["num"] as! Int }
    .scan(0) { some, new in
    new > some ? new : some
    }
    .distinctUntilChanged()
    .subscribe(onNext: { ... })
    .addDisposableTo(disposeBag)

    View full-size slide

  51. scanͷಛ௃
    อ͍࣋ͯ͠ΔΞΠςϜ͕มΘΔࡍʹɺݹ͍ΞΠςϜΛར༻ͯ͠ॲ
    ཧΛߦ͏Α͏ͳ͜ͱ΋Մೳɻ

    View full-size slide

  52. Good Stream
    botton.rx.tap
    .flatMapLatest {
    URLSession.shared.rx.json(request: request)
    }
    .map { json in json["num"] as! Int }
    .scan(0) { some, new in
    if new > some {
    ...
    return new
    }
    return some
    }
    .distinctUntilChanged()
    .subscribe(onNext: { ... })
    .addDisposableTo(disposeBag)

    View full-size slide

  53. distinctUntilChanged

    View full-size slide

  54. distinctUntilChanged
    ॏෳͨ͠ΞΠςϜͷ৔߹͸ૹ৴͠ͳ͍Α͏ʹ͢ΔΦϖϨʔλɻ

    View full-size slide

  55. distinctUntilChanged
    botton.rx.tap
    .flatMapLatest {
    URLSession.shared.rx.json(request: request)
    }
    .map { json in json["num"] as! Int }
    .distinctUntilChanged()
    .subscribe(onNext: { ... })
    .addDisposableTo(disposeBag)

    View full-size slide

  56. distinctUntilChangedͷಛ௃
    ΞΠςϜ͕EquatableͰ͸ͳ͍৔߹͸ΫϩʔδϟΛड͚औͬͯͦ
    ͷΫϩʔδϟΛ࣮ߦ͠ɺ໭Γ஋͕trueͷ͏ͪ͸ॲཧΛܧଓ͠ͳ
    ͍Α͏ͳৼΔ෣͍Λ͍ͯ͠Δɻ

    View full-size slide

  57. distinctUntilChangedͷಛ௃
    ετϦʔϜʹྲྀΕͨΞΠςϜΛอ͓͖࣋ͯ͠ɺ࣍ճετϦʔϜʹ
    ΞΠςϜ͕ྲྀΕ͖ͯͨࡍʹ৽چ྆ํͷΞΠςϜΛಘΔ͜ͱ͕Մ
    ೳɻ
    ॳظ஋Λؾʹ͠ͳ͍ͷͰ͋Ε͹ɺscanͱಉ͡Α͏ͳॲཧΛ΋͏
    গ͠୹͘ॻ͘͜ͱ΋Ͱ͖Δɻ

    View full-size slide

  58. distinctUntilChanged
    botton.rx.tap
    .flatMapLatest {
    URLSession.shared.rx.json(request: request)
    }
    .map { json in json["num"] as! Int }
    .distinctUntilChanged { old, new in
    if (new <= old) == false {
    ...
    }
    return new <= old
    }
    .subscribe(onNext: { ... })
    .addDisposableTo(disposeBag)

    View full-size slide