Slide 1

Slide 1 text

ReactorKit Ͱςετ ͠΍͘͢͢Δ USAMI Kosuke Fenrir Inc.

Slide 2

Slide 2 text

ࣗݾ঺հ • Ӊࠤݟެี @usamik26 • ϑΣϯϦϧגࣜձࣾ • iOS ΞϓϦ։ൃ Swift / C# (Xamarin)

Slide 3

Slide 3 text

தࠃʹߦ͖ͬͯͨ • ੒౎ ඈ࿛Պٕ • iOS ΞϓϦ։ൃϝϯόͱٕज़ަྲྀ • ੒౎ϝϯόʔ͸ ReactorKit Λ࢖ͬ ͍ͯͨ

Slide 4

Slide 4 text

ReactorKit ͱ͸ • RxSwift • Fluxʢ୯ํ޲ϑϩʔʣ • ܰྔͳϑϨʔϜϫʔΫ

Slide 5

Slide 5 text

Design Goal • Testability : View ͱϩδοΫͷ෼཭ • Start Small : ΞϓϦͷҰ෦͚ͩͰ΋ద༻Ͱ͖Δ • Less Typing : ίʔυΛෳࡶʹ͠ͳ͍

Slide 6

Slide 6 text

Testability • ςετՄೳੑɺςετ༰қੑ • ࠓճ͸ Testability ʹ஫໨ͯ͠ ReactorKit ΛݟͯΈΔ

Slide 7

Slide 7 text

ߏ੒ਤ

Slide 8

Slide 8 text

View ͱ Reactor • View ͷ੹຿ (1) • UI ૢ࡞ → Action ͱͯ͠ Reactor ʹ౉͢ • Reactor ͷ੹຿ • Action → ॲཧΛߦ͍ State Λੜ੒͢Δ • View ͷ੹຿ (2) • State → UI ʹදࣔ͢Δ

Slide 9

Slide 9 text

੹຿ͷ෼཭ • UIViewController ʹ͸ View ͷ੹຿͚ͩΛ࣋ͨͤΔ • Reactor ͸ผΦϒδΣΫτͱͯ͠෼཭ʢͳ͓ɺReactor ͸ UIKit ͸࢖Θͳ͍ʣ • ͜ΕʹΑΓ Testability ͕޲্͢Δ • ࠓճ͸ಛʹ View ͷ Testability ΛݟͯΈΔ

Slide 10

Slide 10 text

View ϓϩτίϧ class MyViewController: View { func bind(reactor: MyReactor) { // ͜͜Ͱ Reactor ͱͷόΠϯσΟϯάΛߦ͏ // RxSwift Λ׆༻ } }

Slide 11

Slide 11 text

Reactor ϓϩτίϧ class MyReactor: Reactor { enum Action { case myAction case myActionWithArg(Int) } struct State { var myValue1 = "" var myValue2 = false } }

Slide 12

Slide 12 text

View ͷόΠϯσΟϯά : Action func bind(reactor: MyReactor) { myButton.rx.tap .map { Reactor.Action.myAction } .bind(to: reactor.action) .disposed(by: self.disposeBag) ʢͳ͓ɺreactor.action ͸ ActionSubjectʣ

Slide 13

Slide 13 text

View ͷόΠϯσΟϯά : State func bind(reactor: MyReactor) { reactor.state .map { $0.myValue1 } .bind(to: myLabel.rx.text) .disposed(by: self.disposeBag) ʢͳ͓ɺreactor.state ͸ Observableʣ

Slide 14

Slide 14 text

Reactor ͷॲཧ : mutate() • Action Λड͚औͬͯ Observable Λฦ͢ • ۩ମతͳॲཧʢWeb API ࣮ߦɺσʔλϕʔεΞΫηεɺͳͲʣ Λߦ͏ Observable Λੜ੒͢Δ • ࣮ࡍʹॲཧΛߦ͏͔Ͳ͏͔ͷ൑அͳͲ͸ Reactor ͷ໾໨ • ͜ΕʹΑΓɺView ଆͰ͸ Action Λੜ੒͢Δ͔Ͳ͏͔Λ൑ அ͠ͳ͍ͨΊɺView ͷ࣮૷͕όΠϯσΟϯά͚ͩͰ͢Ή

Slide 15

Slide 15 text

Reactor ͷॲཧ : reduce() • Mutation ͱલͷ State Λड͚औͬͯ State Λฦ͢ • ॲཧͷ݁Ռͱલͷঢ়ଶΛߟྀͯ࣍͠ͷঢ়ଶΛܾΊΔͷ͕໾໨ • ͜ΕʹΑΓɺView ଆͰ͸લͷঢ়ଶΛߟྀ͢Δͱ͍ͬͨॲཧ͕ ෆཁʹͳΔͨΊɺView ͷ࣮૷͕όΠϯσΟϯά͚ͩͰ͢Ή

Slide 16

Slide 16 text

View ͷ୯ମςετΛߟ͑Δ • ୯ମςετͰԿΛ͢Δ΂͖͔ʁ • ʮͦͷΦϒδΣΫτͷ੹຿ΛՌ͍ͨͯ͠Δ͔ʯΛςετ͢Δ • View ͷ੹຿ (1) : UI ૢ࡞ → Action • View ͷ੹຿ (2) : State → UI දࣔ

Slide 17

Slide 17 text

View ͷςετ : Action • ίʔυͰ UI ૢ࡞Λൃੜͤ͞Δ • myButton.sendActions(for .touchUpInside) • ͦͷ݁Ռͱͯ͠ɺReactor ʹ Action ΦϒδΣΫτ͕౉͞Ε ͨ͜ͱΛ֬ೝ͍ͨ͠ • Ͳ͏΍ͬͯʁ ʹ Reactor ͷελϒΛ༻ҙ͢Ε͹͍͍ • ࣮͸ ReactorKit Ͱ͸ελϒ͕͢Ͱʹ༻ҙ͞Ε͍ͯΔ

Slide 18

Slide 18 text

View ͷςετ : Action func testMyAction() { let reactor = MyReactor() reactor.stub.isEnabled = true let view = MyView() view.reactor = reactor view.myButton.sendActions(for .touchUpInside) XCTAssertEqual(reactor.stub.actions.last, .myAction) }

Slide 19

Slide 19 text

View ͷςετ : State • ΍͸Γ Reactor ͷελϒΛ׆༻͢Δ • ίʔυͰ Reactor ͷ State มԽΛى͜͢ • ͦͷ݁Ռͱͯ͠ɺUI ද͕ࣔมߋ͞Εͨ͜ͱΛ֬ೝ͢Δ

Slide 20

Slide 20 text

View ͷςετ : State func testMyAction() { let reactor = MyReactor() reactor.stub.isEnabled = true let view = MyView() view.reactor = reactor reactor.stub.state.value = MyReactor.State(myValue1: "abc") XCTAssertEqual(view.myLabel.text, "abc") }

Slide 21

Slide 21 text

View ͷςετ·ͱΊ • Կ͕ςετͰ͖ͨͷ͔ʁ : View ͕੹຿ΛՌ͍ͨͯ͠Δ͜ͱ • View ͷ࣮૷ͱͯ͠͸όΠϯσΟϯά͕ͪΌΜͱͰ͖͍ͯΔ͜ ͱ • ͦ΋ͦ΋ςετඞཁʁ : Testability ޲্ͷͨΊγϯϓϧ ͳΦϒδΣΫτʹͳͬͨ݁Ռɺ୯७͗ͯ͢ςετෆཁͰ͸ͱ͍ ͏Ϩϕϧʹ • ࣮ࡍʹςετίʔυΛॻ͔͘Ͳ͏͔͸έʔεόΠέʔε

Slide 22

Slide 22 text

Reactor ͷ୯ମςετʢུ֓ʣ • ʮͦͷΦϒδΣΫτͷ੹຿ΛՌ͍ͨͯ͠Δ͔ʯΛςετ͢Δ • Reactor ͷ੹຿ : Action → State • ίʔυͰ Action Λൃੜͤͯ͞ɺState มߋΛ֬ೝ͢Δ • Reactor ͸ View ΁ͷґଘ͕ͳ͍ͨΊɺಠཱͯ͠ςετՄೳ

Slide 23

Slide 23 text

Reactor ͷ୯ମςετʢུ֓ʣ • Reactor ͷதͰ Web API ࣮ߦɺσʔλϕʔεΞΫηεɺͳ Ͳ͕͋Δͱ୯ମςετ͠ʹ͘͘ͳΔ • ͦ͜ͰɺͦΕΒΛ Service ͱͯ͠ Reactor ͷ֎ʹ੾Γग़͢ • Service ΛελϒԽ͢Δ͜ͱͰ Reactor ͕୯ମςετՄೳ

Slide 24

Slide 24 text

·ͱΊ • ෳ਺ͷ੹຿Λ͕࣋ͪͪͳ UIViewController ʹ͍ͭͯɺ ReactorKit Ͱ View ͱ Reactor ʹ੹຿Λ෼཭ͨ͠ • ͜ΕʹΑΓɺView ΍ Reactor ͕ςετՄೳʹͳͬͨ