Slide 1

Slide 1 text

RxFeedback࢖ͬͯΈͨ Nagoya iOS Meetup Vol.1 2018.1
 @katoyan_

Slide 2

Slide 2 text

ࣗݾ঺հ • @katoyan_ • ͓ͱͱ໊͠ݹ԰ʹUλʔϯ͖ͯ͠·ͨ͠ • ࢓ࣄ
 iOS, αʔόαΠυ • ࠷ۙ͸Ծ૝௨՟ʹϋϚͬͯ·͢

Slide 3

Slide 3 text

RxSwift࢖ͬͯ·͔͢ʁ

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

RxSwiftͰ։ൃ͢Δͱ͖
 ΞʔΩςΫνϟͬͯԿ͕ྑ͍ΜͩΖ͏ʁ MVVM? Flux/Redux? Clean Architecture?

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

IUUQTHJUIVCDPNCFFUIWFO3Y4XJGU$IJOFTF%PDVNFOUBUJPO

Slide 8

Slide 8 text

RxFeedback • Try! Swift NYC (2017.11)
 Modern RxSwift Architectures by Krunoslav Zaher • https://github.com/NoTests/RxFeedback.swift • ݕࡧͯ͠΋υΩϡϝϯτগɻɻ

Slide 9

Slide 9 text

RxFeedbackͷߏ଄ The simplest architecture for RxSwift IUUQTHJUIVCDPN/P5FTUT3Y'FFECBDLTXJGU

Slide 10

Slide 10 text

͋ΕʁReduxʹࣅͯΔؾ͕͢Δ

Slide 11

Slide 11 text

IUUQTBDBEFNZSFBMNJPQPTUTUSZTXJGUOZDLSVOPTMBW[BIFSNPEFSOSYTXJGUBSDIJUFDUVSFT 3FEVY͸"QQMJDBUJPO-FWFMͰͭͷେ͖ͳ4UBUF͕ඞཁɻ 3Y'FFECBDL͸7JFX$POUSPMMFS୯ҐͰ4UBUFΛ࣋ͭ͜ͱ΋Մೳɻ ఻ൖίετ͕Լ͕Δ

Slide 12

Slide 12 text

typealias Feedback = (Observable) -> Observable public static func system( initialState: State, reduce: @escaping (State, Event) -> State, feedback: Feedback... ) -> Observable w JOJUJBM4UBUFॳظ4UBUFΛࢦఆ w SFEVDF&WFOUΛड͚औͬͯɺ4UBUFΛมߋ͢ΔॲཧΛఆٛ w GFFECBDL4UBUFͷมߋΛ΋ͱʹ6*Λมߋͨ͠Γɺ&WFOUΛൃՐͤ͞Δॲ ཧΛఆٛ Observable.systemPSDriver.systemͰݺͼग़͠ Interface

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

RxFeedbackͰΞϓϦΛ࡞ͬͯΈͨ Ծ૝௨՟"1*ΛϦΫΤετͯ݁͠ՌΛ 6*5BCMF7JFXͰදࣔ SFGSFTI$POUSPMMͰ݁ՌΛϦϑϨογϡ 6*5BCMF7JFXͷҰ൪Լ·ͰεΫϩʔϧͨ͠ Βଓ͖ͷσʔλΛऔಘ

Slide 15

Slide 15 text

State struct State { // ಡΈࠐΈϖʔδ਺ var loadPage: Int? = 1 // ಡΈࠐΈத͔ var loading: Bool = false // ΞΠςϜϦετ var items: [Coin] = [] }

Slide 16

Slide 16 text

Event enum Event { // ϦϑϨογϡ case refresh // ࣍ͷϖʔδΛϦΫΤετ case loadNextPage // Ϩεϙϯε case response([Coin]) }

Slide 17

Slide 17 text

Reducer reduce: { (state: State, event: Event) -> State in switch event { case .refresh: var results = state results.loadPage = 1 results.loading = true results.items = [] return results case .loadNextPage: var results = state results.loadPage = (results.items.count / fetchCount) + 1 results.loading = true return results case .response(let items): var results = state results.loadPage = nil results.loading = false results.items += items return results } }

Slide 18

Slide 18 text

Feedback feedback: bind(self) { me, state in let subscriptions: [Disposable] = [ // itemsΛUITableViewʹBind state.map { $0.items } .drive(me.tableView.rx.items(cellIdentifier: "Cell"))(me.configureCell), // loading ͕falseͰ͋Ε͹refreshControlΛఀࢭ state.map { $0.loading }.filter { !$0 } .drive(onNext: { _ in me.refreshControl.endRefreshing() }) ] let events: [Signal] = [ // RefreshControl͕มߋ͞ΕΕ͹refreshΠϕϯτΛൃՐͤ͞Δ me.refreshControl.rx.controlEvent(.valueChanged).asSignal().map { _ in Event.refresh }, // UITableViewΛఈ·ͰεΫϩʔϧͨ͠৔߹͸loadNextPageΠϕϯτΛൃՐͤ͞Δ state.flatMapLatest { state in if state.loading { return Signal.empty() } return me.tableView.rx.reachedBottom.map { _ in Event.loadNextPage } } ] return Bindings(subscriptions: subscriptions, events: events) }, react(query: { $0.loadPage }, effects: { page in // loadPage͕มߋ͞ΕΔ౓ʹݺ͹ΕΔ(nilͷ৔߹͸ݺ͹Εͳ͍) return api.fetch(page: page, limit: fetchCount) .asSignal(onErrorJustReturn: []) .map(Event.response) })

Slide 19

Slide 19 text

DEMO

Slide 20

Slide 20 text

࢖ͬͯΈͨॴײ • State ͱ Event ͷઃܭ͕େࣄ • ໾ׂ͕໌֬ʹͳͬͯΔ͜ͱͰɺՄಡੑ͸ྑ͘ͳͬͨ • RxFeedback Λ࢖͏લͱൺ΂Δͱهड़ྔ͸ݮͬͨ • υΩϡϝϯτʢαϯϓϧʣ͕গͳ͍ͷͰਏ͔ͬͨ

Slide 21

Slide 21 text

͓ΘΓ https://github.com/yukatou/CryptoChecker-RxFeedback