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

入門 ReactiveSwift / Introduction to ReactiveSwift

入門 ReactiveSwift / Introduction to ReactiveSwift

Studio Rookery

November 22, 2018
Tweet

Other Decks in Programming

Transcript

  1. ೖ໳
    ReactiveSwift
    XFE

    View full-size slide

  2. ΋͘͡
    •ൃදͷಈػ
    •λʔήοτͱ࠷ऴ໨ඪ
    •ReactiveSwift ͷ֓ཁ
    •Signal / SignalProducer
    •Property / MutableProperty
    •όΠϯσΟϯάԋࢉࢠ
    •Action
    •·ͱΊ
    2

    View full-size slide

  3. ؀ڥ
    3
    ߲໨ όʔδϣϯ
    Xcode 10.0.0
    Swift 4.2
    Result 4.0.0
    ReactiveSwift 4.0.0
    ReactiveCocoa 8.0.2
    RxSwift 4.3.1
    RxCocoa 4.3.1

    View full-size slide

  4. ൃදͷಈػ
    4

    View full-size slide

  5. ൃදͷಈػ
    • RxSwiftΛ1೥൒͘Β͍࢖ͬͯͨ
    • ࢖͍͜ͳ͖͕ͤͯͨͦΕͱಉ࣌ʹෆຬ΋ग़͖ͯͨ
    • ReactiveSwiftͷ͜ͱ͕ؾʹͳ͖ͬͯͨ
    • ReactiveSwift࢖ͬͯΈͨΒͱͯ΋ศརͩͬͨ
    • ࠓ·Ͱແ৚݅ʹ RxSwift ΛબΜͰ͍͕ͨ΋ͬͱ৭ʑࢼ͢΂͖ͩͬ
    ͨ
    • ಉ͡Α͏ͳਓ͕͍Δ͔΋͠Εͳ͍͠೔ຊޠͷ৘ใগͳ͍ͷͰൃද͠
    Α͏
    5

    View full-size slide

  6. ൃදͷಈػ
    • RxSwiftΛ1೥൒͘Β͍࢖ͬͯͨ
    • ࢖͍͜ͳ͖͕ͤͯͨͦΕͱಉ࣌ʹෆຬ΋ग़͖ͯͨ
    • ReactiveSwiftͷ͜ͱ͕ؾʹͳ͖ͬͯͨ
    • ReactiveSwift࢖ͬͯΈͨΒͱͯ΋ศརͩͬͨ
    • ࠓ·Ͱແ৚݅ʹ RxSwift ΛબΜͰ͍͕ͨ΋ͬͱ৭ʑࢼ͢΂͖ͩͬ
    ͨ
    • ಉ͡Α͏ͳਓ͕͍Δ͔΋͠Εͳ͍͠೔ຊޠͷ৘ใগͳ͍ͷͰൃද͠
    Α͏
    6

    View full-size slide

  7. ൃදͷಈػ
    • RxSwiftΛ1೥൒͘Β͍࢖ͬͯͨ
    • ࢖͍͜ͳ͖͕ͤͯͨͦΕͱಉ࣌ʹෆຬ΋ग़͖ͯͨ
    • ReactiveSwiftͷ͜ͱ͕ؾʹͳ͖ͬͯͨ
    • ReactiveSwift࢖ͬͯΈͨΒͱͯ΋ศརͩͬͨ
    • ࠓ·Ͱແ৚݅ʹ RxSwift ΛબΜͰ͍͕ͨ΋ͬͱ৭ʑࢼ͢΂͖ͩͬ
    ͨ
    • ಉ͡Α͏ͳਓ͕͍Δ͔΋͠Εͳ͍͠೔ຊޠͷ৘ใগͳ͍ͷͰൃද͠
    Α͏
    7

    View full-size slide

  8. ൃදͷಈػ
    • RxSwiftΛ1೥൒͘Β͍࢖ͬͯͨ
    • ࢖͍͜ͳ͖͕ͤͯͨͦΕͱಉ࣌ʹෆຬ΋ग़͖ͯͨ
    • ReactiveSwiftͷ͜ͱ͕ؾʹͳ͖ͬͯͨ
    • ReactiveSwift࢖ͬͯΈͨΒͱͯ΋ศརͩͬͨ
    • ࠓ·Ͱແ৚݅ʹ RxSwift ΛબΜͰ͍͕ͨ΋ͬͱ৭ʑࢼ͢΂͖ͩͬ
    ͨ
    • ಉ͡Α͏ͳਓ͕͍Δ͔΋͠Εͳ͍͠೔ຊޠͷ৘ใগͳ͍ͷͰൃද͠
    Α͏
    8

    View full-size slide

  9. ൃදͷಈػ
    • RxSwiftΛ1೥൒͘Β͍࢖ͬͯͨ
    • ࢖͍͜ͳ͖͕ͤͯͨͦΕͱಉ࣌ʹෆຬ΋ग़͖ͯͨ
    • ReactiveSwiftͷ͜ͱ͕ؾʹͳ͖ͬͯͨ
    • ReactiveSwift࢖ͬͯΈͨΒͱͯ΋ศརͩͬͨ
    • ࠓ·Ͱແ৚݅ʹ RxSwift ΛબΜͰ͍͕ͨ΋ͬͱ৭ʑࢼ͢΂͖ͩͬ
    ͨ
    • ಉ͡Α͏ͳਓ͕͍Δ͔΋͠Εͳ͍͠೔ຊޠͷ৘ใগͳ͍ͷͰൃද͠
    Α͏
    9

    View full-size slide

  10. ൃදͷಈػ
    • RxSwiftΛ1೥൒͘Β͍࢖ͬͯͨ
    • ࢖͍͜ͳ͖͕ͤͯͨͦΕͱಉ࣌ʹෆຬ΋ग़͖ͯͨ
    • ReactiveSwiftͷ͜ͱ͕ؾʹͳ͖ͬͯͨ
    • ReactiveSwift࢖ͬͯΈͨΒͱͯ΋ศརͩͬͨ
    • ࠓ·Ͱແ৚݅ʹ RxSwift ΛબΜͰ͍͕ͨ΋ͬͱ৭ʑࢼ͢΂͖ͩͬ
    ͨ
    • ಉ͡Α͏ͳਓ͕͍Δ͔΋͠Εͳ͍͠೔ຊޠͷ৘ใগͳ͍ͷͰൃද͠
    Α͏
    10

    View full-size slide

  11. λʔήοτͱ࠷ऴ໨ඪ
    11

    View full-size slide

  12. λʔήοτ
    • RxSwift ೿
    • ಛʹཧ༝͸ͳ͍͚Ͳ RxSwift ͔͠࢖ͬͨ͜ͱͳ͍೿
    • RxSwift Α͏ߟ͑ͨΒ೉͍͠ΜͪΌ͏ʁͱࢥͬͯΔ೿
    • ͋Δఔ౓ Rx ͕෼͔Δਓ
    12

    View full-size slide

  13. ࠷ऴ໨ඪ
    Rx ͷϑϨʔϜϫʔΫΛબͿࡍʹ
    ReactiveSwift Λબ୒ࢶʹೖΕͯཉ͍͠
    13

    View full-size slide

  14. ͜ͷൃදͷओࢫͱ͸ؔ܎ແ͍͜ͱ
    • ReactiveExtensions Λ࠾༻͢Δ͔Ͳ͏͔
    • ͲΜͳΞʔΩςΫνϟΛ࠾༻͢Δ͔
    14

    View full-size slide

  15. ReactiveSwift ͷ֓ཁ
    15

    View full-size slide

  16. ߏ੒
    16
    for PureSwift ReactiveSwift
    for Cocoa ReactiveCocoa
    Dependency Result

    View full-size slide

  17. ߏ੒
    17
    for PureSwift ReactiveSwift
    for Cocoa ReactiveCocoa
    Dependency Result

    View full-size slide

  18. 18
    antitypical/Result

    View full-size slide

  19. 19
    ґଘϥΠϒϥϦ͋Δͷʁʢ৺഑ʣ

    View full-size slide

  20. 20
    Result ͸ศརʂ
    ୯ମͰ΋࢖͍͍ͨ͘Β͍༗༻
    ͔ͩΒେৎ෉"

    View full-size slide

  21. 21
    ඪ४ϥΠϒϥϦʹ௥Ճ͢Δϓϩϙʔβϧʂ

    View full-size slide

  22. ReactiveSwift Λߏ੒͢Δओͳίϯϙʔωϯτ
    • Signal
    • SignalProducer
    • Property
    • MutableProperty
    • όΠϯσΟϯάԋࢉࢠ
    • Action
    22

    View full-size slide

  23. Signal/SignalProducer
    24

    View full-size slide

  24. Signal/SignalProducer ͷ֓ཁ
    • RxSwift Ͱ͍͏ `Observable`
    • Hot ͳ Observable ͕ Signal
    • Cold ͳ Observable ͕ SignalProducer
    25

    View full-size slide

  25. Signal
    27
    • Hot ͳ Observable
    • subscribe ͞ΕΔલ͔Βಈ͍͍ͯΔʢ͓͞Β͍ʣ
    • ΤϥʔΛܕύϥϝʔλͱͯ࣋ͭ͠

    View full-size slide

  26. ࢖ͬͯΈΔ
    28
    let (users, observer) = Signal.pipe()
    let userNames: Signal = users.map { $0.name }
    userNames.observeValues { userName in
    print(userName)
    }
    observer.send(value: User(id: 123, name: "fenrir"))
    observer.sendCompleted()

    View full-size slide

  27. ࢖ͬͯΈΔ
    29
    let (users, observer) = Signal.pipe()
    let userNames: Signal = users.map { $0.name }
    userNames.observeValues { userName in
    print(userName)
    }
    observer.send(value: User(id: 123, name: "fenrir"))
    observer.sendCompleted()
    pipe ϝιουͰ Signal ͱ
    ͦͷ Input Λ࡞੒͢Δ

    View full-size slide

  28. ࢖ͬͯΈΔ
    30
    let (users, observer) = Signal.pipe()
    let userNames: Signal = users.map { $0.name }
    userNames.observeValues { userName in
    print(userName)
    }
    observer.send(value: User(id: 123, name: "fenrir"))
    observer.sendCompleted()
    Signal
    ग़ྗ୲౰

    View full-size slide

  29. ࢖ͬͯΈΔ
    31
    let (users, observer) = Signal.pipe()
    let userNames: Signal = users.map { $0.name }
    userNames.observeValues { userName in
    print(userName)
    }
    observer.send(value: User(id: 123, name: "fenrir"))
    observer.sendCompleted()
    Signal.Observer
    ೖྗ୲౰

    View full-size slide

  30. ࢖ͬͯΈΔ
    32
    let (users, observer) = Signal.pipe()
    let userNames: Signal = users.map { $0.name }
    userNames.observeValues { userName in
    print(userName)
    }
    observer.send(value: User(id: 123, name: "fenrir"))
    observer.sendCompleted()
    map ϝιουͰ User → String ͷ Signal ΁ม׵
    RxSwift ͱҧͬͯ map ͯ͠΋ Hot(=Signal) ͷ··ʂ

    View full-size slide

  31. ࢖ͬͯΈΔ
    33
    let (users, observer) = Signal.pipe()
    let userNames: Signal = users.map { $0.name }
    userNames.observeValues { userName in
    print(userName)
    }
    observer.send(value: User(id: 123, name: "fenrir"))
    observer.sendCompleted()
    `observe` ܥͷϝιουͰ Signal Λߪಡ͢Δ
    RxSwift Ͱ͸͓ͳ͡Έͷ
    disposed(by:) ૬౰ͷॲཧ͸লུͰ͖Δ

    View full-size slide

  32. ࢖ͬͯΈΔ
    34
    let (users, observer) = Signal.pipe()
    let userNames: Signal = users.map { $0.name }
    userNames.observeValues { userName in
    print(userName)
    }
    observer.send(value: User(id: 123, name: "fenrir"))
    observer.sendCompleted()
    ΠϕϯτΛૹ৴͢Δ
    ೖྗͱग़ྗ͕ผͷΦϒδΣΫτʹ෼͔Ε͍ͯΔͷͰ
    Readonly ͳ Signal Λ࡞Γ΍͍͢

    View full-size slide

  33. ͓͞Β͍
    35
    “Signal Λ map ͯ͠΋
    Signal ͷ··”
    Ͱ͋Δ͜ͱͷԿ͕خ͍͠ʁ

    View full-size slide

  34. RxSwift ͩͱ
    36
    let subject = PublishSubject()
    let userNames = subject.map { user -> String in
    print("map ͨ͠Α☺ (RxSwift)")
    return user.name
    }
    // 2 ճ subscribe ͢Δ
    let disposeBag = DisposeBag()
    userNames
    .subscribe(onNext: { name in
    print(name)
    })
    .disposed(by: disposeBag)
    userNames
    .subscribe(onNext: { name in
    print(name)
    })
    .disposed(by: disposeBag)
    // ΠϕϯτΛૹΔ
    subject.onNext(User(id: 123, name: "fenrir"))
    subject.onCompleted()

    View full-size slide

  35. RxSwift ͩͱ
    37
    let subject = PublishSubject()
    let userNames = subject.map { user -> String in
    print("map ͨ͠Α☺ (RxSwift)")
    return user.name
    }
    // 2 ճ subscribe ͢Δ
    let disposeBag = DisposeBag()
    userNames
    .subscribe(onNext: { name in
    print(name)
    })
    .disposed(by: disposeBag)
    userNames
    .subscribe(onNext: { name in
    print(name)
    })
    .disposed(by: disposeBag)
    // ΠϕϯτΛૹΔ
    subject.onNext(User(id: 123, name: "fenrir"))
    subject.onCompleted()
    pipe ͷ୅ΘΓʹ࢖͏

    PublishSubject ͸ Hot

    View full-size slide

  36. RxSwift ͩͱ
    38
    let subject = PublishSubject()
    let userNames = subject.map { user -> String in
    print("map ͨ͠Α☺ (RxSwift)")
    return user.name
    }
    // 2 ճ subscribe ͢Δ
    let disposeBag = DisposeBag()
    userNames
    .subscribe(onNext: { name in
    print(name)
    })
    .disposed(by: disposeBag)
    userNames
    .subscribe(onNext: { name in
    print(name)
    })
    .disposed(by: disposeBag)
    // ΠϕϯτΛૹΔ
    subject.onNext(User(id: 123, name: "fenrir"))
    subject.onCompleted()
    map ͢Δͱ cold ʹͳΔ

    View full-size slide

  37. RxSwift ͩͱ
    39
    let subject = PublishSubject()
    let userNames = subject.map { user -> String in
    print("map ͨ͠Α☺ (RxSwift)")
    return user.name
    }
    // 2 ճ subscribe ͢Δ
    let disposeBag = DisposeBag()
    userNames
    .subscribe(onNext: { name in
    print(name)
    })
    .disposed(by: disposeBag)
    userNames
    .subscribe(onNext: { name in
    print(name)
    })
    .disposed(by: disposeBag)
    // ΠϕϯτΛૹΔ
    subject.onNext(User(id: 123, name: "fenrir"))
    subject.onCompleted()
    Կճ map ͞Ε͔ͨ෼͔ΔΑ͏
    ϩάΛ࢓ࠐΜͰ͓͘

    View full-size slide

  38. RxSwift ͩͱ
    40
    let subject = PublishSubject()
    let userNames = subject.map { user -> String in
    print("map ͨ͠Α☺ (RxSwift)")
    return user.name
    }
    // 2 ճ subscribe ͢Δ
    let disposeBag = DisposeBag()
    userNames
    .subscribe(onNext: { name in
    print(name)
    })
    .disposed(by: disposeBag)
    userNames
    .subscribe(onNext: { name in
    print(name)
    })
    .disposed(by: disposeBag)
    // ΠϕϯτΛૹΔ
    subject.onNext(User(id: 123, name: "fenrir"))
    subject.onCompleted()
    subscribe ͨ͠਺͚ͩ

    Observable ͕ੜ੒͞ΕΔ

    ɾϝϞϦͷແବݣ͍

    ɾόάͷݪҼ

    ʹͳΓಘΔ
    ɹɹɹ

    View full-size slide

  39. RxSwift ͩͱ
    41
    let subject = PublishSubject()
    let userNames = subject.map { user -> String in
    print("map ͨ͠Α☺ (RxSwift)")
    return user.name
    }
    // 2 ճ subscribe ͢Δ
    let disposeBag = DisposeBag()
    userNames
    .subscribe(onNext: { name in
    print(name)
    })
    .disposed(by: disposeBag)
    userNames
    .subscribe(onNext: { name in
    print(name)
    })
    .disposed(by: disposeBag)
    // ΠϕϯτΛૹΔ
    subject.onNext(User(id: 123, name: "fenrir"))
    subject.onCompleted()
    subscribe ͨ͠਺͚ͩ

    Observable ͕ੜ੒͞ΕΔ

    ɾϝϞϦͷແବݣ͍

    ɾόάͷݪҼ

    ʹͳΓಘΔ
    ɹɹɹ$࣮ߦ݁Ռ
    ʹͬ͜Γͯ͠Δ৔߹Ͱ͸ͳ͍

    View full-size slide

  40. RxSwift ͩͱ
    • Hot ͔ Cold ͔ਓ͕ؒ஫ҙͯ͠औΓѻΘͳ͚Ε͹ͳΒͳ͍
    42

    View full-size slide

  41. RxSwift ͩͱ
    • Hot ͔ Cold ͔ਓ͕ؒ஫ҙͯ͠औΓѻΘͳ͚Ε͹ͳΒͳ͍
    43
    let userNames = subject // Hot
    .map { user -> String in // Cold
    print("map ͨ͠Α☺ (RxSwift)")
    return user.name
    }
    .share(replay: 1, scope: .forever) // Hot
    ཪͰԿΛ͍ͯ͠Δ͔
    ཧղ͢Δͷ͸೉͍͠%
    Cold → Hot ͷม׵͸Մೳ͕ͩɾɾɾ

    View full-size slide

  42. 44
    Ұํ ReactiveSwift

    View full-size slide

  43. ReactiveSwiftͩͱ
    45
    let (users, observer) = Signal.pipe()
    let userNames: Signal = users.map { user -> String in
    print("map ͨ͠Α☺ (ReactiveSwift)")
    return user.name
    }
    // 2 ճ subscribe ͢Δ
    userNames.observeValues { userName in
    print(userName)
    }
    userNames.observeValues { userName in
    print(userName)
    }
    // ΠϕϯτΛૹΔ
    observer.send(value: User(id: 123, name: "fenrir"))
    observer.sendCompleted()

    View full-size slide

  44. ReactiveSwiftͩͱ
    46
    let (users, observer) = Signal.pipe()
    let userNames: Signal = users.map { user -> String in
    print("map ͨ͠Α☺ (ReactiveSwift)")
    return user.name
    }
    // 2 ճ subscribe ͢Δ
    userNames.observeValues { userName in
    print(userName)
    }
    userNames.observeValues { userName in
    print(userName)
    }
    // ΠϕϯτΛૹΔ
    observer.send(value: User(id: 123, name: "fenrir"))
    observer.sendCompleted()
    Hot ͳ Observable Ͱ͋Δ
    Signal Λ༻ҙ

    View full-size slide

  45. ReactiveSwiftͩͱ
    47
    let (users, observer) = Signal.pipe()
    let userNames: Signal = users.map { user -> String in
    print("map ͨ͠Α☺ (ReactiveSwift)")
    return user.name
    }
    // 2 ճ subscribe ͢Δ
    userNames.observeValues { userName in
    print(userName)
    }
    userNames.observeValues { userName in
    print(userName)
    }
    // ΠϕϯτΛૹΔ
    observer.send(value: User(id: 123, name: "fenrir"))
    observer.sendCompleted()
    map ͯ͠΋ Signal ͳ··ʂ

    View full-size slide

  46. ReactiveSwiftͩͱ
    48
    let (users, observer) = Signal.pipe()
    let userNames: Signal = users.map { user -> String in
    print("map ͨ͠Α☺ (ReactiveSwift)")
    return user.name
    }
    // 2 ճ subscribe ͢Δ
    userNames.observeValues { userName in
    print(userName)
    }
    userNames.observeValues { userName in
    print(userName)
    }
    // ΠϕϯτΛૹΔ
    observer.send(value: User(id: 123, name: "fenrir"))
    observer.sendCompleted()
    Կճ subscribe ͯ͠΋
    map ͸ 1 ౓͔࣮͠ߦ͞Εͳ͍

    View full-size slide

  47. ReactiveSwiftͩͱ
    • Hot ͔ Cold ͔೰·ͣͱ΋ܕΛݟΕ͹෼͔Δʂ
    • ಄Λ೰·ͤΔඞཁ͕ͳ͍ʂ
    • Hot ΛΦϖϨʔλͰܨ͍Ͱ΋ Hot ͷ··ʂ
    49

    View full-size slide

  48. 50
    ࿩Λগ͠લ·Ͱ໭͠·͢

    View full-size slide

  49. ʢ࠶ܝʣ࢖ͬͯΈΔ
    51
    let (users, observer) = Signal.pipe()
    let userNames: Signal = users.map { $0.name }
    userNames.observeValues { userName in
    print(userName)
    }
    observer.send(value: User(id: 123, name: "fenrir"))
    observer.sendCompleted()
    Signal Λߪಡ͢Δ
    RxSwift Ͱ͸͓ͳ͡Έͷ
    disposed(by:) ૬౰ͷॲཧ͸লུͰ͖Δ

    View full-size slide

  50. ʢ࠶ܝʣ࢖ͬͯΈΔ
    52
    let (users, observer) = Signal.pipe()
    let userNames: Signal = users.map { $0.name }
    userNames.observeValues { userName in
    print(userName)
    }
    observer.send(value: User(id: 123, name: "fenrir"))
    observer.sendCompleted()
    Signal Λߪಡ͢Δ
    RxSwift Ͱ͸͓ͳ͡Έͷ
    disposed(by:) ૬౰ͷॲཧ͸লུͰ͖Δ

    View full-size slide

  51. 53
    ໌ࣔతʹ dispose ͠ͳͯ͘΋͍͍ʁ

    View full-size slide

  52. 55
    ͏Μ
    ʢ·͋ঢ়گʹΑΔ͚Ͳʣ

    View full-size slide

  53. 56
    interrupted Πϕϯτൃੜ࣌ʹ
    dispose ͞ΕΔ

    View full-size slide

  54. interrupted ʹΑΔ dispose
    57
    var (users, observer) = Signal.pipe()
    let userNames: Signal = users.map { $0.name }
    userNames.observeValues { userName in
    print(userName)
    }
    observer.send(value: User(id: 123, name: "fenrir"))
    // ݩʑͷΠϯελϯεΛഁغ͢Δ
    (users, observer) = Signal.pipe()

    View full-size slide

  55. interrupted ʹΑΔ dispose
    58
    var (users, observer) = Signal.pipe()
    let userNames: Signal = users.map { $0.name }
    userNames.observeValues { userName in
    print(userName)
    }
    observer.send(value: User(id: 123, name: "fenrir"))
    // ݩʑͷΠϯελϯεΛഁغ͢Δ
    (users, observer) = Signal.pipe()
    Կ͔͠ΒͷݪҼͰ
    Signal ͷΠϯελϯε͕
    ղ์͞ΕΔͱɾɾɾ

    View full-size slide

  56. interrupted ʹΑΔ dispose
    59
    var (users, observer) = Signal.pipe()
    let userNames: Signal = users.map { $0.name }
    userNames.observeValues { userName in
    print(userName)
    }
    observer.send(value: User(id: 123, name: "fenrir"))
    // ݩʑͷΠϯελϯεΛഁغ͢Δ
    (users, observer) = Signal.pipe()
    Signal ͔Β `interrupted` Πϕϯτ͕఻ୡ͞ΕΔ
    `completed` or `failed` ͢Δલʹ
    ऴΘͬͪΌͬͨΑͱ͍͏ҙຯ

    View full-size slide

  57. Signal.Event
    60
    public enum Event {
    case value(Value)
    case failed(Error)
    case completed
    case interrupted
    }

    View full-size slide

  58. Signal.Event
    61
    public enum Event {
    case value(Value)
    case failed(Error)
    case completed
    case interrupted
    }
    ஋ΛૹΔΠϕϯτ
    RxSwift Ͱ͸ next

    View full-size slide

  59. Signal.Event
    62
    public enum Event {
    case value(Value)
    case failed(Error)
    case completed
    case interrupted
    }
    ࣦഊΛૹΔΠϕϯτ
    RxSwift Ͱ͸ error
    ड͚औΔͱdispose͞ΕΔ

    View full-size slide

  60. Signal.Event
    63
    public enum Event {
    case value(Value)
    case failed(Error)
    case completed
    case interrupted
    }
    ׬ྃΛૹΔΠϕϯτ
    RxSwift Ͱ΋ completed
    ड͚औΔͱdispose͞ΕΔ

    View full-size slide

  61. Signal.Event
    64
    public enum Event {
    case value(Value)
    case failed(Error)
    case completed
    case interrupted
    }
    ߪಡ͕Ωϟϯηϧ͞Εͨ͜ͱ
    ΛૹΔΠϕϯτ
    ड͚औΔͱdispose͞ΕΔ
    RxSwift ʹ͸ͳ͍

    View full-size slide

  62. interrupted ʹΑΔ dispose
    • `interrupted` ͕ى͜Δͱࣗಈతʹ dispose ͞ΕΔ
    • ͜ΕʹΑΓ RxSwift ͷ disposed(by:) ૬౰ͷॲཧ͕

    লུͰ͖Δʂ
    • RxSwift ͷ “DisposeBag Λఆٛͯ͠ disposed(by:) ͠
    ͯ…” ͱ͍͏͍ͭ΋ॻ͘ΞϨ͕ແ͘ͳΔ
    65

    View full-size slide

  63. खಈͰ dispose ΋Ͱ͖ΔΑ
    66
    // ͖ͬ͞·ͰӅΕͯͨ
    let disposable = userNames.observeValues { userName in
    print(userName)
    }
    • खಈͰ΋ dispose Ͱ͖Δ
    • subscribe ܥͷϝιουͷฦΓ஋͕ RxSwift ͱಉ༷
    Disposable
    • @discardableResult ʹͳ͍ͬͯΔͷͰීஈ͸͋·Γ
    ҙࣝ͠ͳ͍

    View full-size slide

  64. SignalProducer
    67

    View full-size slide

  65. SignalProducer
    68
    • Cold ͳ Observable
    • subscribe ͞Ε͔ͯΒಈ͘ʢ͓͞Β͍ʣ
    • ΤϥʔΛܕύϥϝʔλͱͯ࣋ͭ͠

    View full-size slide

  66. 69
    ͍࣋ͬͯΔΠϯλʔϑΣʔε͸΄΅
    Signal ͱಉ͡

    View full-size slide

  67. ࢖ͬͯΈΔ
    70
    let request = URLRequest(url: URL(string: "https://example.com/")!)
    let session = URLSession.shared
    let data: SignalProducer<(Data, URLResponse), AnyError> = session.reactive.data(with: request)
    data.startWithResult { result in
    switch result {
    case .success(let data, let response):
    break
    case .failure(let error):
    print(error)
    }
    }
    `startͳΜͨΒ`ܥͷϝιουΛݺͿ͜ͱͰॳΊͯಈ࡞͢Δ
    ྫͰ͸ `startWithResult` ΛݺΜͰ͍Δ
    ·ͨɺSignal ಉ༷ dispose ͷॲཧ͸লུͰ͖Δ

    View full-size slide

  68. RxSwift ͱൺֱͭͭ͠SignalProducerΛ࡞ͬͯΈΔ
    71
    // subscribe ͞ΕͨΒಉظతʹ1ͭͷ value ͱ completed Λྲྀ͢
    SignalProducer(value: 1) // ReactiveSwift
    Observable.just(1) // RxSwift
    // subscribe ͞ΕͨΒಉظతʹ error Λྲྀ͢
    SignalProducer(error: APIError.network) // ReactiveSwift
    Observable.error(APIError.network) // RxSwift
    // subscribe ͞ΕͨΒಉظతʹ completed Λྲྀ͢
    SignalProducer.empty // ReactiveSwift
    Observable.empty() // RxSwift

    View full-size slide

  69. RxSwift ͱൺֱͭͭ͠SignalProducerΛ࡞ͬͯΈΔ
    72
    // subscribe ͞ΕͨΒಉظతʹ1ͭͷ value ͱ completed Λྲྀ͢
    SignalProducer(value: 1) // ReactiveSwift
    Observable.just(1) // RxSwift
    // subscribe ͞ΕͨΒಉظతʹ error Λྲྀ͢
    SignalProducer(error: APIError.network) // ReactiveSwift
    Observable.error(APIError.network) // RxSwift
    // subscribe ͞ΕͨΒಉظతʹ completed Λྲྀ͢
    SignalProducer.empty // ReactiveSwift
    Observable.empty() // RxSwift
    ඇಉظόʔδϣϯ΋࡞ͬͯΈΔ

    View full-size slide

  70. ඇಉظSignalProducer࡞ͬͯΈΔ
    73
    func fetchUsers(with name: String) -> SignalProducer<[User], APIError> {
    return SignalProducer<[User], APIError> { observer, lifetime in
    repository.fetchUsers(with: name) { result in
    switch result {
    case .success(let users):
    observer.send(value: users)
    observer.sendCompleted()
    case .failure(let error):
    observer.send(error: error)
    }
    }
    }
    }

    View full-size slide

  71. ඇಉظSignalProducer࡞ͬͯΈΔ
    74
    func fetchUsers(with name: String) -> SignalProducer<[User], APIError> {
    return SignalProducer<[User], APIError> { observer, lifetime in
    repository.fetchUsers(with: name) { result in
    switch result {
    case .success(let users):
    observer.send(value: users)
    observer.sendCompleted()
    case .failure(let error):
    observer.send(error: error)
    }
    }
    }
    }
    public init(_ startHandler: @escaping (Signal.Observer, Lifetime) -> Void)
    ΠχγϟϥΠβͷҾ਺͸ΫϩʔδϟΛ1ͭ

    View full-size slide

  72. ඇಉظSignalProducer࡞ͬͯΈΔ
    75
    func fetchUsers(with name: String) -> SignalProducer<[User], APIError> {
    return SignalProducer<[User], APIError> { observer, lifetime in
    repository.fetchUsers(with: name) { result in
    switch result {
    case .success(let users):
    observer.send(value: users)
    observer.sendCompleted()
    case .failure(let error):
    observer.send(error: error)
    }
    }
    }
    }
    `start` ͞ΕΔͱΠχγϟϥΠβʹ౉ͨ͠
    Ϋϩʔδϟ͕࣮ߦ͞ΕΔ

    View full-size slide

  73. ඇಉظSignalProducer࡞ͬͯΈΔ
    76
    func fetchUsers(with name: String) -> SignalProducer<[User], APIError> {
    return SignalProducer<[User], APIError> { observer, lifetime in
    repository.fetchUsers(with: name) { result in
    switch result {
    case .success(let users):
    observer.send(value: users)
    observer.sendCompleted()
    case .failure(let error):
    observer.send(error: error)
    }
    }
    }
    }
    ࣗ࡞Ϋϥεͷࣗ࡞ϝιου
    ඇಉظॲཧͳͷͰҾ਺ʹ completionHandler ΛऔΔ

    View full-size slide

  74. ඇಉظSignalProducer࡞ͬͯΈΔ
    77
    func fetchUsers(with name: String) -> SignalProducer<[User], APIError> {
    return SignalProducer<[User], APIError> { observer, lifetime in
    repository.fetchUsers(with: name) { result in
    switch result {
    case .success(let users):
    observer.send(value: users)
    observer.sendCompleted()
    case .failure(let error):
    observer.send(error: error)
    }
    }
    }
    }
    ඇಉظॲཧ͕ऴΘͬͨΒ࣮ߦ͞ΕΔ

    View full-size slide

  75. ඇಉظSignalProducer࡞ͬͯΈΔ
    78
    func fetchUsers(with name: String) -> SignalProducer<[User], APIError> {
    return SignalProducer<[User], APIError> { observer, lifetime in
    repository.fetchUsers(with: name) { result in
    switch result {
    case .success(let users):
    observer.send(value: users)
    observer.sendCompleted()
    case .failure(let error):
    observer.send(error: error)
    }
    }
    }
    }
    ݁ՌʹԠͯ͡ Observer ʹΠϕϯτΛૹΔ
    ʢ͜ͷล͸ RxSwift ͱͦΜͳʹมΘΒͳ͍Ͱ͢ʣ

    View full-size slide

  76. 79
    ͱ͜ΖͰΤϥʔͷछྨ͕ܕϨϕϧͰΘ͔Δ͜ͱͷ
    ͳʹ͕خ͍͠ʁ

    View full-size slide

  77. 80
    Ͳ͏ͤ localizeDescription ͔͠
    ࢖ΘΜ͠ͳʙ

    View full-size slide

  78. ΤϥʔλΠϓͷϝϦοτ
    • ΤϥʔͷछྨʹԠͯ͡ॲཧΛ੾Γ෼͚͍ͨͱ͖ͳͲ

    →ʮτʔΫϯ੾Εͷ࣌ͷΈ࠶౓ϩάΠϯॲཧΛཪͰߦ͏ʯͱ͔


    Τϥʔͷछྨ͕Θ͔Βͳ͍ͱΩϟετ͠ͳ͚Ε͹ͳΒͳ͍ɻ

    ࣮ߦ͢Δ·ͰΩϟετ͕੒ޭ͢Δ͔Ͳ͏͔͸෼͔Βͳ͍…
    • Τϥʔ͕ى͖ͳ͍͜ͱΛදݱͰ͖Δ

    → NoError Λ࢖͏͜ͱͰΤϥʔϋϯυϦϯά͠ͳͯ͘΋͍
    ͍ʂͱ͍͏͜ͱ͕Θ͔Δɻ
    82
    Τϥʔʹؔ͢Δॲཧ͕ίϯύΠϧ࣌ʹอূ͞ΕΔʂ

    View full-size slide

  79. 83
    Signal/SignalProducer
    ͓͞Β͍

    View full-size slide

  80. 84
    RxSwift ͱൺֱ

    View full-size slide

  81. ReactiveSwift VS RxSwift
    85
    ReactiveSwift RxSwift
    Hot Signal Observable
    Cold
    Signal
    Producer
    Observable
    Τϥʔͷܕ ෼͔Δ ෼͔ΒΜ
    disposeΛলུ Ͱ͖Δ Ͱ͖ͳ͍

    View full-size slide

  82. ReactiveSwift VS RxSwift
    86
    ReactiveSwift RxSwift
    Hot Signal Observable
    Cold
    Signal
    Producer
    Observable
    Τϥʔͷܕ ෼͔Δ ෼͔ΒΜ
    disposeΛলུ Ͱ͖Δ Ͱ͖ͳ͍
    ܕϨϕϧͰ Hot ͔ Cold ͷ۠ผ͕ͭ͘

    View full-size slide

  83. ReactiveSwift VS RxSwift
    87
    ReactiveSwift RxSwift
    Hot Signal Observable
    Cold
    Signal
    Producer
    Observable
    Τϥʔͷܕ ෼͔Δ ෼͔ΒΜ
    disposeΛলུ Ͱ͖Δ Ͱ͖ͳ͍
    ܕϨϕϧͰΤϥʔͷछྨͷ۠ผ͕ͭ͘
    `NoError`Λ࢖͑͹Τϥʔ͕ى͖ͳ͍͜ͱΛදݱͰ͖Δ

    View full-size slide

  84. ReactiveSwift VS RxSwift
    88
    ReactiveSwift RxSwift
    Hot Signal Observable
    Cold
    Signal
    Producer
    Observable
    Τϥʔͷܕ ෼͔Δ ෼͔ΒΜ
    disposeΛলུ Ͱ͖Δ Ͱ͖ͳ͍
    RxSwiftͱൺ΂ָͯͰ͖Δ
    ϚχϡΞϧ dispose ΋Ͱ͖Δ

    View full-size slide

  85. 89
    Signal ͱ SignalProducer ͱͰൺֱ

    View full-size slide

  86. Signal VS SignalProducer
    90
    Signal SignalProducer
    Hot/Cold Hot Cold
    ߪಡ։࢝ͷϝιου observeXXX startXXX
    ओͳੜ੒ํ๏ Signal.pipe() ৭ʑ͋Δ

    View full-size slide

  87. Signal VS SignalProducer
    91
    Signal SignalProducer
    Hot/Cold Hot Cold
    ߪಡ։࢝ͷϝιου observeXXX startXXX
    ओͳੜ੒ํ๏ Signal.pipe() ৭ʑ͋Δ
    ໋໊ͷҧ͍͕྆ऀͷҧ͍ΛࡍཱͨͤͯΔʢͱࢥ͏ʣ

    View full-size slide

  88. Signal VS SignalProducer
    92
    Signal SignalProducer
    Hot/Cold Hot Cold
    ߪಡ։࢝ͷϝιου observeXXX startXXX
    ओͳੜ੒ํ๏ Signal.pipe() ৭ʑ͋Δ
    ߪಡ։࢝͢Δ͝ͱʹ start ͞ΕΔΜͩͳ͊
    ͱײ͡ΒΕΔ໋໊

    View full-size slide

  89. Signal/SignalProducer
    ͓͠·͍
    93

    View full-size slide

  90. Property/MutableProperty
    94

    View full-size slide

  91. MutableProperty
    95

    View full-size slide

  92. MutableProperty
    96
    • ߪಡՄೳͳ஋Λอ͍࣋ͯ͠Δ
    • ஋ͷมߋ͸ Signal / SignalProducer ͔ΒߪಡՄೳ
    • ಉظతʹ஋Λऔಘɾઃఆ͢Δ͜ͱ΋Ͱ͖Δ
    • RxSwift Ͱ͍͏ BehaviorRelay(چVariable)
    • ໊લ͕Θ͔Γ΍͍͢
    • ReactiveSwift ʹఆٛ͞Ε͍ͯΔʢBehaviorRelay ͸
    RxCocoaʹఆٛ͞Ε͍ͯΔʣ

    View full-size slide

  93. ࢖ͬͯΈΔ
    97
    let selectedUsers = MutableProperty<[User]>([])
    // ஋ͷมߋΛ `Signal` Ͱ subscribe
    selectedUsers.signal.observeValues { selectedUsers in
    print(selectedUsers)
    }
    // ஋ͷมߋΛ `SignalProducer` Ͱ subscribe
    selectedUsers.producer.startWithValues { selectedUsers in
    print(selectedUsers)
    }
    // ஋ͷมߋͱऔಘ͸ value ͔ΒՄೳ
    selectedUsers.value = [
    User(id: 123, name: "fenrir")
    ]
    selectedUsers.value.removeAll()
    XCTAssert(selectedUsers.value.isEmpty)

    View full-size slide

  94. ࢖ͬͯΈΔ
    98
    let selectedUsers = MutableProperty<[User]>([])
    // ஋ͷมߋΛ `Signal` Ͱ subscribe
    selectedUsers.signal.observeValues { selectedUsers in
    print(selectedUsers)
    }
    // ஋ͷมߋΛ `SignalProducer` Ͱ subscribe
    selectedUsers.producer.startWithValues { selectedUsers in
    print(selectedUsers)
    }
    // ஋ͷมߋͱऔಘ͸ value ͔ΒՄೳ
    selectedUsers.value = [
    User(id: 123, name: "fenrir")
    ]
    selectedUsers.value.removeAll()
    XCTAssert(selectedUsers.value.isEmpty)
    ॳظԽ

    View full-size slide

  95. let selectedUsers = MutableProperty<[User]>([])
    // ஋ͷมߋΛ `Signal` Ͱ subscribe
    selectedUsers.signal.observeValues { selectedUsers in
    print(selectedUsers)
    }
    // ஋ͷมߋΛ `SignalProducer` Ͱ subscribe
    selectedUsers.producer.startWithValues { selectedUsers in
    print(selectedUsers)
    }
    // ஋ͷมߋͱऔಘ͸ value ͔ΒՄೳ
    selectedUsers.value = [
    User(id: 123, name: "fenrir")
    ]
    selectedUsers.value.removeAll()
    XCTAssert(selectedUsers.value.isEmpty)
    ࢖ͬͯΈΔ
    99
    ஋ͷมߋΛߪಡͰ͖Δ
    ॳظ஋͸ྲྀΕͯ͜ͳ͍

    View full-size slide

  96. let selectedUsers = MutableProperty<[User]>([])
    // ஋ͷมߋΛ `Signal` Ͱ subscribe
    selectedUsers.signal.observeValues { selectedUsers in
    print(selectedUsers)
    }
    // ஋ͷมߋΛ `SignalProducer` Ͱ subscribe
    selectedUsers.producer.startWithValues { selectedUsers in
    print(selectedUsers)
    }
    // ஋ͷมߋͱऔಘ͸ value ͔ΒՄೳ
    selectedUsers.value = [
    User(id: 123, name: "fenrir")
    ]
    selectedUsers.value.removeAll()
    XCTAssert(selectedUsers.value.isEmpty)
    ࢖ͬͯΈΔ
    100
    ஋ͷมߋΛߪಡͰ͖Δ
    ॳظ஋͕ྲྀΕͯདྷΔ

    View full-size slide

  97. let selectedUsers = MutableProperty<[User]>([])
    // ஋ͷมߋΛ `Signal` Ͱ subscribe
    selectedUsers.signal.observeValues { selectedUsers in
    print(selectedUsers)
    }
    // ஋ͷมߋΛ `SignalProducer` Ͱ subscribe
    selectedUsers.producer.startWithValues { selectedUsers in
    print(selectedUsers)
    }
    // ஋ͷมߋͱऔಘ͸ value ͔ΒՄೳ
    selectedUsers.value = [
    User(id: 123, name: "fenrir")
    ]
    selectedUsers.value.removeAll()
    XCTAssert(selectedUsers.value.isEmpty)
    ࢖ͬͯΈΔ
    101
    ஋Λಉظతʹ

    औಘɾઃఆͰ͖Δ

    View full-size slide

  98. Property
    103
    • ಡΈऔΓઐ༻
    • MutableProperty ͱΠϯλʔϑΣʔε͸΄΅ಉ͡
    • RxSwift ʹ͸ಉ༷ͷΫϥε͸ଘࡏ͠ͳ͍
    • ֎෦ʹެ։͢Δ࣌ʹศར

    View full-size slide

  99. ࢖ͬͯΈΔ(1)
    104
    let mutableState = MutableProperty(State.notLoaded)
    mutableState.value = .loading
    let state = Property(capturing: mutableState)
    state.value = .notLoaded

    View full-size slide

  100. let mutableState = MutableProperty(State.notLoaded)
    mutableState.value = .loading
    let state = Property(capturing: mutableState)
    state.value = .notLoaded
    ࢖ͬͯΈΔ(1)
    105
    લड़ͷ௨ΓMutableProperty͸
    ஋Λߋ৽Ͱ͖Δ

    View full-size slide

  101. let mutableState = MutableProperty(State.notLoaded)
    mutableState.value = .loading
    let state = Property(capturing: mutableState)
    state.value = .notLoaded
    ࢖ͬͯΈΔ(1)
    106
    mutableProperty Λ Property ʹม׵
    ஋͸ৗʹݩͱͳͬͨ mutableProperty ͱಉ͡

    View full-size slide

  102. let mutableState = MutableProperty(State.notLoaded)
    mutableState.value = .loading
    let state = Property(capturing: mutableState)
    state.value = .notLoaded
    ࢖ͬͯΈΔ(1)
    107
    ಡΈऔΓઐ༻ͳͷͰίϯύΠϧΤϥʔ
    →Cannot assign to property: 'value' is a get-only property

    View full-size slide

  103. ࢖ͬͯΈΔ(2)
    108
    struct ViewModel {
    let state: Property
    private let mutableState: MutableProperty
    init() {
    self.mutableState = MutableProperty(.notLoaded)
    self.state = Property(capturing: mutableState)
    }
    }

    View full-size slide

  104. struct ViewModel {
    let state: Property
    private let mutableState: MutableProperty
    init() {
    self.mutableState = MutableProperty(.notLoaded)
    self.state = Property(capturing: mutableState)
    }
    }
    ࢖ͬͯΈΔ(2)
    109
    ֎෦΁ͷެ։͸ಡΈऔΓઐ༻Ͱ͋Δ
    Property Λ༻ҙ

    View full-size slide

  105. struct ViewModel {
    let state: Property
    private let mutableState: MutableProperty
    init() {
    self.mutableState = MutableProperty(.notLoaded)
    self.state = Property(capturing: mutableState)
    }
    }
    ࢖ͬͯΈΔ(2)
    110
    ಺෦Ͱ͸ঢ়ଶΛมߋͰ͖ΔΑ͏ʹ
    MutablePropertyͰ͓࣋ͬͯ͘

    View full-size slide

  106. struct ViewModel {
    let state: Property
    private let mutableState: MutableProperty
    init() {
    self.mutableState = MutableProperty(.notLoaded)
    self.state = Property(capturing: mutableState)
    }
    }
    ࢖ͬͯΈΔ(2)
    111
    ֎෦ʹެ։͢Δ༻ͷ Property ͸
    ݩʑ͸ MutableProperty ͳͷͰ

    View full-size slide

  107. struct ViewModel {
    let state: Property
    private let mutableState: MutableProperty
    init() {
    self.mutableState = MutableProperty(.notLoaded)
    self.state = Property(capturing: mutableState)
    }
    }
    ࢖ͬͯΈΔ(2)
    112
    ͍ͭ͜Λม͑Δͱ

    View full-size slide

  108. struct ViewModel {
    let state: Property
    private let mutableState: MutableProperty
    init() {
    self.mutableState = MutableProperty(.notLoaded)
    self.state = Property(capturing: mutableState)
    }
    }
    ࢖ͬͯΈΔ(2)
    113
    ͍ͭ͜΋มΘΔ

    View full-size slide

  109. ͪΐͬͱ·ͱΊ
    • Property ͸ಡΈऔΓઐ༻
    • MutableProperty ͸ಡΈॻ͖Մೳ
    • ͦΕҎ֎ͷΠϯλʔϑΣʔε͸΄΅ಉ͡
    114

    View full-size slide

  110. 115
    Property/MutableProperty
    ͷ map ͕ศར

    View full-size slide

  111. 116
    ʮϢʔβ໊Λ4จࣈҎ্ೖྗ͠ͳ͍ͱ
    ొ࿥Ϙλϯ͕ΞΫςΟϒʹͳΒͳ͍ը໘ʯ
    ͷ ViewModel

    View full-size slide

  112. Property ͷ map ͕ศར
    117
    struct ViewModel {
    let userName: MutableProperty
    let isEnabled: Property
    init() {
    self.userName = MutableProperty("")
    self.isEnabled = userName.map { userName in
    userName.count >= 4
    }
    }
    }

    View full-size slide

  113. Property ͷ map ͕ศར
    118
    struct ViewModel {
    let userName: MutableProperty
    let isEnabled: Property
    init() {
    self.userName = MutableProperty("")
    self.isEnabled = userName.map { userName in
    userName.count >= 4
    }
    }
    }
    ೖྗதͷϢʔβʔ໊
    ͜͜ʹόΠϯυͯ͠΄͍͠

    View full-size slide

  114. Property ͷ map ͕ศར
    119
    struct ViewModel {
    let userName: MutableProperty
    let isEnabled: Property
    init() {
    self.userName = MutableProperty("")
    self.isEnabled = userName.map { userName in
    userName.count >= 4
    }
    }
    }
    ੾Γସ͑ϩδοΫ͸Ӆṭ͍ͨͨ͠Ί
    ಡΈऔΓઐ༻ʹͯ͠Δ

    View full-size slide

  115. Property ͷ map ͕ศར
    120
    struct ViewModel {
    let userName: MutableProperty
    let isEnabled: Property
    init() {
    self.userName = MutableProperty("")
    self.isEnabled = userName.map { userName in
    userName.count >= 4
    }
    }
    }
    userNameͷ஋͕ܾ·Ε͹
    isEnabledͷ஋͸Ұҙʹܾ·Δ
    mapϝιουΛ࢖͑͹ΑΓએݴతʹ͔͚Δ

    View full-size slide

  116. 121
    BehaviorRelayʹ΋
    mapϝιου͸͋Δ͕ɾɾɾ

    View full-size slide

  117. let fenrir = "fenrir"
    let array: Array = Array(arrayLiteral: fenrir).map { $0.count }
    let property: Property = Property(value: fenrir).map { $0.count }
    let mutable: Property = MutableProperty(fenrir).map { $0.count }
    let relay: Observable = BehaviorRelay(value: fenrir).map { $0.count }

    View full-size slide

  118. let fenrir = "fenrir"
    let array: Array = Array(arrayLiteral: fenrir).map { $0.count }
    let property: Property = Property(value: fenrir).map { $0.count }
    let mutable: Property = MutableProperty(fenrir).map { $0.count }
    let relay: Observable = BehaviorRelay(value: fenrir).map { $0.count }
    Array ← map ← Array

    View full-size slide

  119. let fenrir = "fenrir"
    let array: Array = Array(arrayLiteral: fenrir).map { $0.count }
    let property: Property = Property(value: fenrir).map { $0.count }
    let mutable: Property = MutableProperty(fenrir).map { $0.count }
    let relay: Observable = BehaviorRelay(value: fenrir).map { $0.count }
    Property ← map ← Property

    View full-size slide

  120. let fenrir = "fenrir"
    let array: Array = Array(arrayLiteral: fenrir).map { $0.count }
    let property: Property = Property(value: fenrir).map { $0.count }
    let mutable: Property = MutableProperty(fenrir).map { $0.count }
    let relay: Observable = BehaviorRelay(value: fenrir).map { $0.count }
    Property ← map ← MutableProperty

    View full-size slide

  121. let fenrir = "fenrir"
    let array: Array = Array(arrayLiteral: fenrir).map { $0.count }
    let property: Property = Property(value: fenrir).map { $0.count }
    let mutable: Property = MutableProperty(fenrir).map { $0.count }
    let relay: Observable = BehaviorRelay(value: fenrir).map { $0.count }
    Property ← map ← MutableProperty
    map ޙͷܕ͕ҧ͏͕ಡΈऔΓઐ༻ʹ͍͔ͨ͠Βʁ
    ͜ΕͰࠔΔ͜ͱ͸͋Μ·Γແ͍
    Ή͠Ζ͋Γ͕͍ͨ

    View full-size slide

  122. let fenrir = "fenrir"
    let array: Array = Array(arrayLiteral: fenrir).map { $0.count }
    let property: Property = Property(value: fenrir).map { $0.count }
    let mutable: Property = MutableProperty(fenrir).map { $0.count }
    let relay: Observable = BehaviorRelay(value: fenrir).map { $0.count }
    Observable ← map ← BehaviorRelay

    View full-size slide

  123. let fenrir = "fenrir"
    let array: Array = Array(arrayLiteral: fenrir).map { $0.count }
    let property: Property = Property(value: fenrir).map { $0.count }
    let mutable: Property = MutableProperty(fenrir).map { $0.count }
    let relay: Observable = BehaviorRelay(value: fenrir).map { $0.count }
    Observable ← map ← BehaviorRelay
    map ޙͷܕ͕ObservableʹͳΔ

    ͜Ε͸Α͘෼͔Βͳ͍

    View full-size slide

  124. 129
    BehaviorRelayʹ΋
    mapϝιου͸͋Δ͕
    Observable ʹͳͬͯ͠·͏

    View full-size slide

  125. 130
    ͦͷͨΊಉظతʹ஋ΛऔΕͳ͍
    → BehaviorRelay.value ʹΞΫηεͰ͖ͳ͍ʂ

    View full-size slide

  126. 131
    Property/MutableProperty
    ͓͞Β͍

    View full-size slide

  127. 132
    RxSwift ͱൺֱ

    View full-size slide

  128. ReactiveSwift VS RxSwift
    133
    ReactiveSwift RxSwift
    ಡΈॻ͖Մೳ MutableProperty BehaviorRelay
    ಡΈऔΓઐ༻ Property -
    ଐ͢ΔϑϨʔϜϫʔΫ ReactiveSwift RxCocoa

    View full-size slide

  129. ReactiveSwift VS RxSwift
    134
    ReactiveSwift RxSwift
    ಡΈॻ͖Մೳ MutableProperty BehaviorRelay
    ಡΈऔΓઐ༻ Property -
    ଐ͢ΔϑϨʔϜϫʔΫ ReactiveSwift RxCocoa
    ଘࡏ͠ͳ͍

    View full-size slide

  130. 135
    PropertyͱMutablePropertyͱͰൺֱ

    View full-size slide

  131. Property VS MutableProperty
    136
    Property MutableProperty
    ಡΈऔΓ ◯ ◯
    ॻ͖ࠐΈ × ◯
    mapޙͷܕ Property Property

    View full-size slide

  132. Property/MutableProperty
    ͓͠·͍
    137

    View full-size slide

  133. <~
    όΠϯσΟϯάԋࢉࢠ
    138

    View full-size slide

  134. όΠϯσΟϯάԋࢉࢠ(<~)
    • ஋ͷόΠϯυʹ࢖͏
    • ͪΐͬͱ໘ന͍
    139

    View full-size slide

  135. ࢖ͬͯΈΔ
    140
    viewModel.userName <~ textField.reactive.continuousTextValues.map { $0 ?? "" }
    registerButton.reactive.isEnabled <~ viewModel.isEnabled

    View full-size slide

  136. viewModel.userName <~ textField.reactive.continuousTextValues.map { $0 ?? "" }
    registerButton.reactive.isEnabled <~ viewModel.isEnabled
    ࢖ͬͯΈΔ
    141
    ͍ͭ͜

    View full-size slide

  137. viewModel.userName <~ textField.reactive.continuousTextValues.map { $0 ?? "" }
    registerButton.reactive.isEnabled <~ viewModel.isEnabled
    ࢖ͬͯΈΔ
    142
    ࠨลʹ͸όΠϯυ͞ΕΔଆΛஔ͘
    ɾMutableProperty
    ɾBindingTarget
    ͳͲ

    View full-size slide

  138. viewModel.userName <~ textField.reactive.continuousTextValues.map { $0 ?? "" }
    registerButton.reactive.isEnabled <~ viewModel.isEnabled
    ࢖ͬͯΈΔ
    143
    ӈลʹ͸஋ΛૹΔଆΛஔ͘
    ɾSignal/SignalProducer
    ɾProperty/MutableProperty
    ͳͲ

    View full-size slide

  139. viewModel.userName <~ textField.reactive.continuousTextValues.map { $0 ?? "" }
    registerButton.reactive.isEnabled <~ viewModel.isEnabled
    ࢖ͬͯΈΔ
    144
    ӈล͕ Property/MutableProperty
    ͷ৔߹͸ݱࡏͷ஋͕ଈྲྀΕͯ͘Δ
    ஋ͷऔΓಀ͕͠Λߟ͑ͳͯ͘ྑ͍

    View full-size slide

  140. ࢖ͬͯΈΔ
    145
    // ࣮͸ӅΕ͍ͯͨ
    registerButton.reactive.isEnabled <~ viewModel.isEnabled

    View full-size slide

  141. // ࣮͸ӅΕ͍ͯͨ
    let disposable = registerButton.reactive.isEnabled <~ viewModel.isEnabled
    ࢖ͬͯΈΔ
    146
    ԋࢉࢠͷ݁Ռ͸ @discardableResult ͳ Disposable
    Signal/SignalProducer ͱಉ༷
    dispose ͷॲཧΛলུͰ͖Δ

    View full-size slide

  142. όΠϯσΟϯάԋࢉࢠ(<~)͓͞Β͍
    • ࠨล͸όΠϯυ͞ΕΔଆ
    • ӈล͸όΠϯυ͢Δଆ
    • ฦΓ஋͸ @discardableResult ͳ Disposable
    • dispose ͸লུՄೳ
    147

    View full-size slide

  143. <~
    όΠϯσΟϯάԋࢉࢠ
    ͓͠·͍
    148

    View full-size slide

  144. Action
    • ໋໊͕ͬ͘͟Γ
    • ཧղ͢Δͷʹ͕͔͔࣌ؒΔ
    • ඇಉظॲཧͷ࣮ߦΛ੍ޚɾ؂ࢹͯ͘͠ΕΔ
    • Input Λ༩͑ͯ Output ΋͘͠͸ Error Λ͸͖ͩ͢
    150

    View full-size slide

  145. Action
    • ໋໊͕ͬ͘͟Γ
    • ཧղ͢Δͷʹ͕͔͔࣌ؒΔ
    • ඇಉظॲཧͷ࣮ߦΛ੍ޚɾ؂ࢹͯ͘͠ΕΔ
    • Input Λ༩͑ͯ Output ΋͘͠͸ Error Λ͸͖ͩ͢
    151

    View full-size slide

  146. 153
    Action
    InputΛ༩͑ͯ

    View full-size slide

  147. 154
    Action
    Output΋͘͠͸

    View full-size slide

  148. 155
    Action
    ErrorΛ͸͖ͩ͢

    View full-size slide

  149. 156
    Ϣʔβʔ໊ͰϢʔβʔҰཡΛ
    ඇಉظͰݕࡧ͢Δ Action

    View full-size slide

  150. ࢖ͬͯΈΔ
    157
    let action = Action { keyword -> SignalProducer<[User], APIError> in
    repository.fetchUsers(name: keyword)
    }
    Input → String (=Ϣʔβʔ໊)
    Output → [User] (=ϢʔβʔҰཡ)
    Error → APIError (=Τϥʔ)

    View full-size slide

  151. ࢖ͬͯΈΔ
    158
    let action = Action { keyword -> SignalProducer<[User], APIError> in
    repository.fetchUsers(name: keyword)
    }
    ΠχγϟϥΠβͷҾ਺͸Ϋϩʔδϟ1ͭ
    ʢଞͷύλʔϯ΋͋Δʣ

    View full-size slide

  152. ࢖ͬͯΈΔ
    159
    let action = Action { keyword -> SignalProducer<[User], APIError> in
    repository.fetchUsers(name: keyword)
    }
    (Input) -> SignalProducer

    View full-size slide

  153. ࢖ͬͯΈΔ
    160
    let action = Action { keyword -> SignalProducer<[User], APIError> in
    repository.fetchUsers(name: keyword)
    }
    (Input) -> SignalProducer

    View full-size slide

  154. ࢖ͬͯΈΔ
    161
    let action = Action { keyword -> SignalProducer<[User], APIError> in
    repository.fetchUsers(name: keyword)
    }
    (Input) -> SignalProducer

    View full-size slide

  155. ࢖ͬͯΈΔ
    162
    let action = Action { keyword -> SignalProducer<[User], APIError> in
    repository.fetchUsers(name: keyword)
    }
    (Input) -> SignalProducer

    View full-size slide

  156. ࢖ͬͯΈΔ
    163
    let action = Action { keyword -> SignalProducer<[User], APIError> in
    repository.fetchUsers(name: keyword)
    }
    action.apply("fenrir").start()

    View full-size slide

  157. ࢖ͬͯΈΔ
    164
    let action = Action { keyword -> SignalProducer<[User], APIError> in
    repository.fetchUsers(name: keyword)
    }
    action.apply("fenrir").start()
    apply ϝιουͰ Input(=String) Λ༩͑Δ

    View full-size slide

  158. ࢖ͬͯΈΔ
    165
    let action = Action { keyword -> SignalProducer<[User], APIError> in
    repository.fetchUsers(name: keyword)
    }
    action.apply("fenrir").start()
    apply → start ͞ΕΔͱ
    ΠχγϟϥΠβʹ౉ͨ͠Ϋϩʔδϟ͕࣮ߦ͞ΕΔ
    ͜ͷΫϩʔδϟͷ໭Γ஋ͷ SignalProducer ͕
    start͞ΕΔ

    View full-size slide

  159. ࢖ͬͯΈΔ
    166
    let action = Action { keyword -> SignalProducer<[User], APIError> in
    repository.fetchUsers(name: keyword)
    }
    action.apply("fenrir").start()
    action.values.observeValues { (users: [User]) in
    print(users)
    }
    action.errors.observeValues { (error: APIError) in
    print(error)
    }
    Output ͸`values`͔ΒऔಘͰ͖Δ

    View full-size slide

  160. ࢖ͬͯΈΔ
    167
    let action = Action { keyword -> SignalProducer<[User], APIError> in
    repository.fetchUsers(name: keyword)
    }
    action.apply("fenrir").start()
    action.values.observeValues { (users: [User]) in
    print(users)
    }
    action.errors.observeValues { (error: APIError) in
    print(error)
    }
    Error ͸`errors`͔ΒऔಘͰ͖Δ

    View full-size slide

  161. ࢖ͬͯΈΔ
    168
    let action = Action { keyword -> SignalProducer<[User], APIError> in
    repository.fetchUsers(name: keyword)
    }
    action.apply("fenrir").start()
    action.values.observeValues { (users: [User]) in
    print(users)
    }
    action.errors.observeValues { (error: APIError) in
    print(error)
    }

    View full-size slide

  162. ࢖ͬͯΈΔ
    169
    let action = Action { keyword -> SignalProducer<[User], APIError> in
    repository.fetchUsers(name: keyword)
    }
    action.apply("fenrir").start()
    action.values.observeValues { (users: [User]) in
    print(users)
    }
    action.errors.observeValues { (error: APIError) in
    print(error)
    }

    View full-size slide

  163. ࢖ͬͯΈΔ
    170
    let action = Action { keyword -> SignalProducer<[User], APIError> in
    repository.fetchUsers(name: keyword)
    }
    action.apply("fenrir").start()
    action.values.observeValues { (users: [User]) in
    print(users)
    }
    action.errors.observeValues { (error: APIError) in
    print(error)
    }
    activityIndicatorView.reactive.isAnimating <~ action.isExecuting

    View full-size slide

  164. ࢖ͬͯΈΔ
    171
    let action = Action { keyword -> SignalProducer<[User], APIError> in
    repository.fetchUsers(name: keyword)
    }
    action.apply("fenrir").start()
    action.values.observeValues { (users: [User]) in
    print(users)
    }
    action.errors.observeValues { (error: APIError) in
    print(error)
    }
    activityIndicatorView.reactive.isAnimating <~ action.isExecuting
    Property
    action ͕࣮ߦ͍ͯ͠ΔؒͷΈ true ʹͳΔ

    View full-size slide

  165. ࢖ͬͯΈΔ
    172
    let action = Action { keyword -> SignalProducer<[User], APIError> in
    repository.fetchUsers(name: keyword)
    }
    action.apply("fenrir").start()
    action.values.observeValues { (users: [User]) in
    print(users)
    }
    action.errors.observeValues { (error: APIError) in
    print(error)
    }
    activityIndicatorView.reactive.isAnimating <~ action.isExecuting
    Πϯδέʔλͷදࣔ੾Γସ͑ͱόΠϯυ͢Δͱ͖ʹศར

    View full-size slide

  166. ࢖ͬͯΈΔ
    173
    let action = Action { keyword -> SignalProducer<[User], APIError> in
    repository.fetchUsers(name: keyword)
    }
    action.apply("fenrir").start()
    action.values.observeValues { (users: [User]) in
    print(users)
    }
    action.errors.observeValues { (error: APIError) in
    print(error)
    }
    activityIndicatorView.reactive.isAnimating <~ action.isExecuting
    action.apply("fenrir").start()
    action.apply("fenrir").start()
    action.apply("fenrir").start()
    action.apply("fenrir").start()

    View full-size slide

  167. ࢖ͬͯΈΔ
    174
    let action = Action { keyword -> SignalProducer<[User], APIError> in
    repository.fetchUsers(name: keyword)
    }
    action.apply("fenrir").start()
    action.values.observeValues { (users: [User]) in
    print(users)
    }
    action.errors.observeValues { (error: APIError) in
    print(error)
    }
    activityIndicatorView.reactive.isAnimating <~ action.isExecuting
    action.apply("fenrir").start()
    action.apply("fenrir").start()
    action.apply("fenrir").start()
    action.apply("fenrir").start()
    Ұ౓ʹ࣮ߦͰ͖ΔΞΫγϣϯ͸1ͭ·Ͱ
    ͢Ͱʹ࣮ߦதͳΒແࢹ͞ΕΔ

    View full-size slide

  168. ࢖ͬͯΈΔ
    175
    let action = Action { keyword -> SignalProducer<[User], APIError> in
    repository.fetchUsers(name: keyword)
    }
    action.apply("fenrir").start()
    action.values.observeValues { (users: [User]) in
    print(users)
    }
    action.errors.observeValues { (error: APIError) in
    print(error)
    }
    activityIndicatorView.reactive.isAnimating <~ action.isExecuting
    action.apply("fenrir").start()
    action.apply("fenrir").start()
    action.apply("fenrir").start()
    action.apply("fenrir").start()
    button.reactive.isEnabled <~ action.isEnabled

    View full-size slide

  169. ࢖ͬͯΈΔ
    176
    let action = Action { keyword -> SignalProducer<[User], APIError> in
    repository.fetchUsers(name: keyword)
    }
    action.apply("fenrir").start()
    action.values.observeValues { (users: [User]) in
    print(users)
    }
    action.errors.observeValues { (error: APIError) in
    print(error)
    }
    activityIndicatorView.reactive.isAnimating <~ action.isExecuting
    action.apply("fenrir").start()
    action.apply("fenrir").start()
    action.apply("fenrir").start()
    action.apply("fenrir").start()
    button.reactive.isEnabled <~ action.isEnabled
    ࣮ߦՄೳ͔Ͳ͏͔ΛόΠϯσΟϯά

    View full-size slide

  170. ࢖ͬͯΈΔ
    177
    // start ͢Δ͚ͩͷύλʔϯ
    action.apply("fenrir").start()
    // start ͯ͠ݸผʹ݁ՌΛϋϯυϦϯά
    action.apply("fenrir").startWithResult { result in
    switch result {
    case .success(let users):
    print(users)
    case .failure(ActionError.disabled):
    print("could not execute")
    case .failure(ActionError.producerFailed(let apiError)):
    print(apiError)
    }
    }

    View full-size slide

  171. ࢖ͬͯΈΔ
    178
    // start ͢Δ͚ͩͷύλʔϯ
    action.apply("fenrir").start()
    // start ͯ͠ݸผʹ݁ՌΛϋϯυϦϯά
    action.apply("fenrir").startWithResult { result in
    switch result {
    case .success(let users):
    print(users)
    case .failure(ActionError.disabled):
    print("could not execute")
    case .failure(ActionError.producerFailed(let apiError)):
    print(apiError)
    }
    }
    ݸผʹϋϯυϦϯά͢Δ͜ͱ΋Ͱ͖Δ
    ݸผʹϋϯυϦϯά͠ͳ͍ύλʔϯ
    ݸผʹϋϯυϦϯά͢Δύλʔϯ

    View full-size slide

  172. ࢖ͬͯΈΔ
    179
    // start ͢Δ͚ͩͷύλʔϯ
    action.apply("fenrir").start()
    // start ͯ͠ݸผʹ݁ՌΛϋϯυϦϯά
    action.apply("fenrir").startWithResult { result in
    switch result {
    case .success(let users):
    print(users)
    case .failure(ActionError.disabled):
    print("could not execute")
    case .failure(ActionError.producerFailed(let apiError)):
    print(apiError)
    }
    }
    ࣮ߦͰ͖ͨ
    ݁Ռ͸੒ޭͩͬͨ

    View full-size slide

  173. ࢖ͬͯΈΔ
    180
    // start ͢Δ͚ͩͷύλʔϯ
    action.apply("fenrir").start()
    // start ͯ͠ݸผʹ݁ՌΛϋϯυϦϯά
    action.apply("fenrir").startWithResult { result in
    switch result {
    case .success(let users):
    print(users)
    case .failure(ActionError.disabled):
    print("could not execute")
    case .failure(ActionError.producerFailed(let apiError)):
    print(apiError)
    }
    }
    ࣮ߦෆՄͷঢ়ଶͩͬͨ

    View full-size slide

  174. ࢖ͬͯΈΔ
    181
    // start ͢Δ͚ͩͷύλʔϯ
    action.apply("fenrir").start()
    // start ͯ͠ݸผʹ݁ՌΛϋϯυϦϯά
    action.apply("fenrir").startWithResult { result in
    switch result {
    case .success(let users):
    print(users)
    case .failure(ActionError.disabled):
    print("could not execute")
    case .failure(ActionError.producerFailed(let apiError)):
    print(apiError)
    }
    }
    ࣮ߦͰ͖ͨ
    ݁Ռ͸ࣦഊͩͬͨ

    View full-size slide

  175. Action͸ͲΜͳ࣌ʹ࢖͑ͦ͏͔
    182
    1. Ϙλϯλοϓ
    2. API ௨৴
    3. ௨৴த͸ΠϯδέʔλΛදࣔ
    4. ੒ޭ࣌: ը໘ભҠ

    ࣦഊ࣌: ΞϥʔτΛදࣔ
    5. ͨͩ͠λοϓ࿈ଧͳͲͰ௨৴͕ೋॏʹ૸Βͳ͍Α͏ʹ੍ޚ͢Δ
    Α͋͘Δύλʔϯʹ࢖͑ͦ͏ʂ

    View full-size slide

  176. Action͸Ԟ͕ਂ͍
    • StateΛ༩͑ͨΓ
    • StateʹԠ࣮ͯ͡ߦͨ͠Γ͠ͳ͔ͬͨΓ
    183
    ৭ʑͰ͖Δʂ

    ৄ͘͠͸υΩϡϝϯτ or ιʔείʔυಡ΋͏ʂ

    View full-size slide

  177. Action ͓͞Β͍
    • ࣮ߦத͔Ͳ͏͔ͷϑϥάΛ Property ͰऔΕΔ
    • ࣮ߦՄೳ͔Ͳ͏͔ͷϑϥάΛ Property ͰऔΕΔ
    • 1౓ʹ࣮ߦͰ͖Δඇಉظॲཧ͸1ͭ·Ͱ
    • APIݺͼग़͠ͱ૬ੑ͕͍͍
    • ֶशίετߴ͍
    184

    View full-size slide

  178. Action
    ͓͠·͍
    185

    View full-size slide

  179. ReactiveSwift·ͱΊ
    • ܕϨϕϧͰ Hot/Cold, Error ͷछྨͱ༗ແ͕൑அͰ͖Δ

    ܕʹݫ͍͠ Swift Β͍͠ϓϩάϥϛϯά͕Ͱ͖Δ
    • ొ৔͢ΔΫϥε͕গͳ͍ͷͰγϯϓϧ
    187

    View full-size slide

  180. ࠓճ࿩ͤͳ͔ͬͨ͜ͱ
    • BindingTarget
    • ReactiveCocoaपΓͷ࿩
    • RxSwiftͷίϨ͸ReactiveSwiftͰ͸͜͏ॻ͘Αͱ͍͏࿩
    • ΋ͬͱ࣮ફతͳ಺༰
    188

    View full-size slide

  181. 189
    ࠷ऴ໨ඪͳΜ΍͚ͬʁ

    View full-size slide

  182. ࠷ऴ໨ඪ
    Rx ͷϑϨʔϜϫʔΫΛબͿࡍʹ
    ReactiveSwift Λબ୒ࢶʹೖΕͯཉ͍͠
    190

    View full-size slide

  183. 191
    ͝ݕ౼͍ͩ͘͞(

    View full-size slide