Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Flux_with_RxSwift.pdf
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Yuji Hato
October 15, 2016
Technology
190
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Flux_with_RxSwift.pdf
Yuji Hato
October 15, 2016
More Decks by Yuji Hato
See All by Yuji Hato
ABEMAにおける 生成AI活用の現在地 / The Current Status of Generative AI at ABEMA
dekatotoro
1
1.2k
ABEMAモバイルアプリ開発のDevOps戦略
dekatotoro
1
730
Multiplatform Engineering Roadmap for the Future
dekatotoro
1
160
Introduction to RIBs
dekatotoro
5
1.4k
継続的な開発スタイル 「AbemaTV iOSアプリを週一で リリースしている話」
dekatotoro
6
4.3k
iOS Adaptive UI - 解像度の異なるデバイスや画面の向きに対応する 最適なレイアウトへ -
dekatotoro
0
540
動画アプリをなめらかに動かす技術 - iOS -
dekatotoro
0
500
5分で学ぶ差分更新とRxDataSources
dekatotoro
0
370
AbemaTV モバイルアプリの開発体制と 開発プロセスの話
dekatotoro
0
290
Other Decks in Technology
See All in Technology
ザ・データベース、MySQL ~ OSC 2026 Sendai ~
sakaik
0
140
脱SaaS!FDEを支えるプロビジョニングと分離設計
knih
0
240
AIチャット検索改善の3週間
kworkdev
PRO
2
140
AIAU_UMEMOGU_ninomiya_slide
ninomiya_ii
0
240
AI-DLCを “そのまま導入しなかった”話 ~組織に合わせてアジャストした 私たちの実践共有~
hiroramos4
PRO
0
230
【Cyber-sec+】経営層を"動かす"ための考え方
hssh2_bin
0
200
SONiCの統計情報を取得したい
sonic
0
230
MUSUBI 田中裕一『AIと共に行う「しごとのリデザイン」- スモールバックオフィス編』AI Ops Lab #4
musubi
0
270
Oracle AI Database@Google Cloud:サービス概要のご紹介
oracle4engineer
PRO
6
1.6k
気軽に使える"情報のハブ"としてのNotion活用 〜フロー情報の集積点 と、 Claude Code × Notion AI〜
syucream
1
160
不要なレビューをAIにまかせて AIコーディングの環境改善を加速した
shoota
1
230
就職⽀援サービスにおけるキャリアアドバイザーのシフトスケジューリング
recruitengineers
PRO
1
150
Featured
See All Featured
[RailsConf 2023] Rails as a piece of cake
palkan
59
6.7k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
3.5k
Making the Leap to Tech Lead
cromwellryan
135
9.9k
Faster Mobile Websites
deanohume
310
31k
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
0
320
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
150
How to Talk to Developers About Accessibility
jct
2
240
Balancing Empowerment & Direction
lara
6
1.2k
A Modern Web Designer's Workflow
chriscoyier
698
190k
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
310
Art, The Web, and Tiny UX
lynnandtonic
304
22k
Crafting Experiences
bethany
1
180
Transcript
Flux with RxSwift AbemaTV Developer Conference 2016 Yuji Hato
About me Yuji Hato CyberAgent, Inc. / AbemaTV, Inc. dekatotoro
@dekatotoro Contributed services
What is Flux?
What is Flux? IUUQTGBDFCPPLHJUIVCJPqVYEPDTPWFSWJFXIUNM “Data in a Flux application flows
in a single direction”
What is Flux? IUUQTHJUIVCDPNGBDFCPPLqVY
What is Flux? IUUQTHJUIVCDPNGBDFCPPLqVY
What is Flux? IUUQTHJUIVCDPNGBDFCPPLqVY Observer ύλʔϯ !
Why Flux?
Why Flux? ࡢࠓͷΞϓϦ։ൃෳࡶԽ ͷҰ్Λḷ͓ͬͯΓঢ়ଶཧ ͕େม
Why Flux? AbemaTVͷঢ়ଶཧ: Cast ΦϯσϚϯυ ՝ۚ CM Filler ը࣭ ࢹௌ༧
etc… ൪ Fresh ίϝϯτ ࢹௌ FullScreen Feed
Why Flux? ͭΒ͍…
Why Flux? UIૢ࡞ɾ࣌ؒʹ͏ෳࡶͳ ঢ়ଶભҠΛ͔Γ͍ͨ͘͢͠
Why Flux? ViewؒͷґଘؔΛݮΒ͍ͨ͠
MVVM MVC DDD Flux Clean Architecture MVP Why Flux? Flux͕͍ͯͦ͏…?
Flux with RxSwift
Flux with RxSwift Action Dispatcher User Interactions API DB ViewController
View Store Events Events
Flux with RxSwift Event StreamͰܨ͍͡Ό͓͏ͥ
Flux with RxSwift Action Dispatcher User Interactions API DB ViewController
View Store Events Events
Flux with RxSwift Dispatcher ViewController View Store Events Events Events
Event̎छྨͷHot ObservableΛ͏
Flux with RxSwift PublishSubject ҰΩϟογϡ͠ͳ͍Subject Events
Flux with RxSwift Variable ۙͷΛ͚̍ͭͩΩϟογϡ͢ΔSubject ※BehaviorSubjectͷwrapper Events
Dispatcher
Dispatcher Action Dispatcher User Interactions API DB ViewController View Store
Events Events
Dispatcher Dispatcherͷϑϩʔ Dispatcher Store Events Events Action Dispatcher Store Store
Events Events Action Action
Dispatcher Action͕dispatch͢Δ Dispatcher Store Store Events Events Action Action on
subscribe
Dispatcher dispatch͞ΕͨΒStore௨ Dispatcher Store Store Events Events Action Action on
subscribe
Dispatcher class DispatchSubject<Element>: ObservableType, ObserverType { typealias E = Element
fileprivate let subject = PublishSubject<E>() func dispatch(_ value: E) { on(.next(value)) } func on(_ event: Event<E>) { subject.on(event) } func subscribe<O: ObserverType>(_ observer: O) -> Disposable where O.E == E { return subject.subscribe(observer) } } Dispatcher༻ͷDispatchSubject
Dispatcher class DispatchSubject<Element>: ObservableType, ObserverType { typealias E = Element
fileprivate let subject = PublishSubject<E>() func dispatch(_ value: E) { on(.next(value)) } func on(_ event: Event<E>) { subject.on(event) } func subscribe<O: ObserverType>(_ observer: O) -> Disposable where O.E == E { return subject.subscribe(observer) } } PublishSubjectͷWrapper
Dispatcher class DispatchSubject<Element>: ObservableType, ObserverType { typealias E = Element
fileprivate let subject = PublishSubject<E>() func dispatch(_ value: E) { on(.next(value)) } func on(_ event: Event<E>) { subject.on(event) } func subscribe<O: ObserverType>(_ observer: O) -> Disposable where O.E == E { return subject.subscribe(observer) } } dispatch͢ΔͱeventΛൃߦ͠·͢
Dispatcher class SomeDispatcher { static let shared = SomeDispatcher() let
loading = DispatchSubject<Bool>() let error = DispatchSubject<Error>() let someModel = DispatchSubject<SomeModel>() … } DispatcherΫϥε
Dispatcher class SomeDispatcher { static let shared = SomeDispatcher() let
loading = DispatchSubject<Bool>() let error = DispatchSubject<Error>() let someModel = DispatchSubject<SomeModel>() … } ActionTypeͷΘΓʹDispatchSubjectΛෳ༻ҙ ※DispatcherΫϥε༻్͝ͱʹ͚ͯ·͢
Dispatcher func someAction(value: Bool) { … dispatcher.loading.dispatch(value) … } Action͕dispatch
Action
Action Action Dispatcher User Interactions API DB ViewController View Store
Events Events
Action Actionͷϑϩʔ Action Action Dispatcher User Interactions API DB ViewController
View Action Action Dispatcher API DB ViewController View Device User Interactions
Action View͔ΒActionΛ࣮ߦ Action Action Dispatcher User Interactions API DB ViewController
View Action Action Dispatcher API DB ViewController View Device User Interactions Action Action Dispatcher User Interactions API DB ViewController View Action Action Action Dispatcher API DB ViewController View Device User Interactions
Action ඞཁͳσʔλΛऔಘ͢Δ Action Action Dispatcher User Interactions API DB ViewController
View Action Action Action Dispatcher API DB ViewController View Device User Interactions
Action UI, Web, DB, DevicesΛ֎෦IFͱͯ͠ଊ͑Δ IUUQTUIMJHIUDPNCMPHVODMFCPCUIFDMFBOBSDIJUFDUVSFIUNM
Action σʔλͷऔಘޙDispatcherྲྀ͢ Action Action Dispatcher User Interactions API DB ViewController
View Action Action Action Dispatcher API DB ViewController View Device User Interactions
Action func someAction(query: String) { dispatcher.loading.dispatch(true) API.getSome(with: query) .do(onError: {
[unowned self] error in self.dispatcher.error.dispatch(error) self.dispatcher.loading.dispatch(false) }) .do(onCompleted: { [unowned self] error in self.dispatcher.loading.dispatch(false) }) .subscribe(onNext: { [unowned self] response in let someModel = SomeModel.make(from: response) self.dispatcher.someModel.dispatch(someModel) }) .addDisposableTo(disposeBag) } APIΛ࣮ߦ͢Δྫ
Action func someAction(query: String) { dispatcher.loading.dispatch(true) API.getSome(with: query) .do(onError: {
[unowned self] error in self.dispatcher.error.dispatch(error) self.dispatcher.loading.dispatch(false) }) .do(onCompleted: { [unowned self] error in self.dispatcher.loading.dispatch(false) }) .subscribe(onNext: { [unowned self] response in let someModel = SomeModel.make(from: response) self.dispatcher.someModel.dispatch(someModel) }) .addDisposableTo(disposeBag) } ϩʔσΟϯάͯ͠API࣮ߦ
Action func someAction(query: String) { dispatcher.loading.dispatch(true) API.getSome(with: query) .do(onError: {
[unowned self] error in self.dispatcher.error.dispatch(error) self.dispatcher.loading.dispatch(false) }) .do(onCompleted: { [unowned self] error in self.dispatcher.loading.dispatch(false) }) .subscribe(onNext: { [unowned self] response in let someModel = SomeModel.make(from: response) self.dispatcher.someModel.dispatch(someModel) }) .addDisposableTo(disposeBag) } Τϥʔͷ࣌
Action func someAction(query: String) { dispatcher.loading.dispatch(true) API.getSome(with: query) .do(onError: {
[unowned self] error in self.dispatcher.error.dispatch(error) self.dispatcher.loading.dispatch(false) }) .do(onCompleted: { [unowned self] error in self.dispatcher.loading.dispatch(false) }) .subscribe(onNext: { [unowned self] response in let someModel = SomeModel.make(from: response) self.dispatcher.someModel.dispatch(someModel) }) .addDisposableTo(disposeBag) } Ϩεϙϯε͕ฦ͖ͬͯͨ࣌
Action func someAction(query: String) { dispatcher.loading.dispatch(true) API.getSome(with: query) .do(onError: {
[unowned self] error in self.dispatcher.error.dispatch(error) self.dispatcher.loading.dispatch(false) }) .do(onCompleted: { [unowned self] error in self.dispatcher.loading.dispatch(false) }) .subscribe(onNext: { [unowned self] response in let someModel = SomeModel.make(from: response) self.dispatcher.someModel.dispatch(someModel) }) .addDisposableTo(disposeBag) } ࣮ߦ͕ྃͨ࣌͠
Store
Store Action Dispatcher User Interactions API DB ViewController View Store
Events Events
Store Storeͷϑϩʔ Dispatcher Store Store ViewController View Events Events Events
Store DispatcherͷeventΛObserve͢Δ Dispatcher Store Store ViewController View Events Events Events
subscribe on on subscribe
Store DispatcherͷΠϕϯτ͕ྲྀΕͯ͘Δ Store Store ViewController View Events Events Events subscribe
on on subscribe Dispatcher
Store DispatcherͷΠϕϯτΛݕͨ͠ΒσʔλΛߋ৽ Store Store ViewController View Events Events Events subscribe
on on subscribe Dispatcher
Store σʔλΛߋ৽ͨ͠ΒView௨ Store Store ViewController View Events Events Events subscribe
subscribe Dispatcher on on
Flux: Store class Store { let disposeBag = DisposeBag() func
bind<O, E>(_ observable: O, _ param: Variable<E>) where O: ObservableType, E == O.E { observable.bindTo(param).addDisposableTo(disposeBag) } func bind<O, E>(_ observable: O, _ param: PublishSubject<E>) where O: ObservableType, E == O.E { observable.bindTo(param).addDisposableTo(disposeBag) } } StoreΫϥε
Flux: Store class Store { let disposeBag = DisposeBag() func
bind<O, E>(_ observable: O, _ param: Variable<E>) where O: ObservableType, E == O.E { observable.bindTo(param).addDisposableTo(disposeBag) } func bind<O, E>(_ observable: O, _ param: PublishSubject<E>) where O: ObservableType, E == O.E { observable.bindTo(param).addDisposableTo(disposeBag) } } Variable༻ͷbind
Flux: Store class Store { let disposeBag = DisposeBag() func
bind<O, E>(_ observable: O, _ param: Variable<E>) where O: ObservableType, E == O.E { observable.bindTo(param).addDisposableTo(disposeBag) } func bind<O, E>(_ observable: O, _ param: PublishSubject<E>) where O: ObservableType, E == O.E { observable.bindTo(param).addDisposableTo(disposeBag) } } PublishSubject༻ͷbind
Flux: Store class SomeStore: Store { static let shared =
SomeStore() let loading = Variable<Bool>(false) let error = PublishSubject<Error>() let someModel = Variable<SomeModel>(SomeModel()) init(dispatcher: SomeDispatcher = .shared) { super.init() bind(dispatcher.loading, loading) bind(dispatcher.error, error) bind(dispatcher.someModel, someModel) } } StoreΫϥε
Flux: Store class SomeStore: Store { static let shared =
SomeStore() let loading = Variable<Bool>(false) let error = PublishSubject<Error>() let someModel = Variable<SomeModel>(SomeModel()) init(dispatcher: SomeDispatcher = .shared) { super.init() bind(dispatcher.loading, loading) bind(dispatcher.error, error) bind(dispatcher.someModel, someModel) } } StoreΫϥεSingleton
Flux: Store class SomeStore: Store { static let shared =
SomeStore() let loading = Variable<Bool>(false) let error = PublishSubject<Error>() let someModel = Variable<SomeModel>(SomeModel()) init(dispatcher: SomeDispatcher = .shared) { super.init() bind(dispatcher.loading, loading) bind(dispatcher.error, error) bind(dispatcher.someModel, someModel) } } StoreͷpropertyVariableͱPublishSubject
Flux: Store class SomeStore: Store { static let shared =
SomeStore() let loading = Variable<Bool>(false) let error = PublishSubject<Error>() let someModel = Variable<SomeModel>(SomeModel()) init(dispatcher: SomeDispatcher = .shared) { super.init() bind(dispatcher.loading, loading) bind(dispatcher.error, error) bind(dispatcher.someModel, someModel) } } initͰdispatcherͱbind
View
View Action Dispatcher User Interactions API DB ViewController View Store
Events Events
View Viewͷϑϩʔ Dispatcher Events Store Store ViewController View Events Action
Action Action User Interactions ViewController View Action
View StoreͱUIͷeventΛObserve͢Δ Dispatcher Events Store Store ViewController View Events subscribe
Action Action User Interactions ViewController View Action
View StoreͷΠϕϯτ͕ྲྀΕͯ͘Δ Dispatcher Events Store Store ViewController View Events on
Action Action User Interactions ViewController View Action
View StoreͷΠϕϯτΛݕͨ͠ΒViewΛߋ৽ Dispatcher Events Store Store ViewController View Events on
Action Action User Interactions ViewController View Action
View UIͷeventΛτϦΨʔʹActionΛ࣮ߦ Dispatcher Events Store Store ViewController View Events Action
Action User Interactions ViewController View Action
View store.loading.asObservable() .distinctUntilChanged() .observeOn(MainScheduler.instance) .subscribe(onNext: { [unowned self] loading in
self.loadingView.hidden(!loading) }) .addDisposableTo(rx_disposeBag) store.error .subscribe(onNext: { error in ErrorAction.show(.apiError(error)) }) .addDisposableTo(rx_disposeBag) store.someModel.asObservable() .map { $0.dataSource } .observeOn(MainScheduler.instance) .subscribe(onNext: { [unowned self] dataSource in self.dataSource.value = dataSource self.tableView?.reloadData() }) .addDisposableTo(rx_disposeBag) Storeͷobserve
View store.loading.asObservable() .distinctUntilChanged() .observeOn(MainScheduler.instance) .subscribe(onNext: { [unowned self] loading in
self.loadingView.hidden(!loading) }) .addDisposableTo(rx_disposeBag) store.error .subscribe(onNext: { error in ErrorAction.show(.apiError(error)) }) .addDisposableTo(rx_disposeBag) store.someModel.asObservable() .map { $0.dataSource } .observeOn(MainScheduler.instance) .subscribe(onNext: { [unowned self] dataSource in self.dataSource.value = dataSource self.tableView?.reloadData() }) .addDisposableTo(rx_disposeBag) StoreͷloadingΛobserve
View store.loading.asObservable() .distinctUntilChanged() .observeOn(MainScheduler.instance) .subscribe(onNext: { [unowned self] loading in
self.loadingView.hidden(!loading) }) .addDisposableTo(rx_disposeBag) store.error .subscribe(onNext: { error in ErrorAction.show(.apiError(error)) }) .addDisposableTo(rx_disposeBag) store.someModel.asObservable() .map { $0.dataSource } .observeOn(MainScheduler.instance) .subscribe(onNext: { [unowned self] dataSource in self.dataSource.value = dataSource self.tableView?.reloadData() }) .addDisposableTo(rx_disposeBag) loadingViewͷදࣔ/ඇදࣔ
View store.loading.asObservable() .distinctUntilChanged() .observeOn(MainScheduler.instance) .subscribe(onNext: { [unowned self] loading in
self.loadingView.hidden(!loading) }) .addDisposableTo(rx_disposeBag) store.error .subscribe(onNext: { error in ErrorAction.show(.apiError(error)) }) .addDisposableTo(rx_disposeBag) store.someModel.asObservable() .map { $0.dataSource } .observeOn(MainScheduler.instance) .subscribe(onNext: { [unowned self] dataSource in self.dataSource.value = dataSource self.tableView?.reloadData() }) .addDisposableTo(rx_disposeBag) StoreͷerrorΛobserve
View store.loading.asObservable() .distinctUntilChanged() .observeOn(MainScheduler.instance) .subscribe(onNext: { [unowned self] loading in
self.loadingView.hidden(!loading) }) .addDisposableTo(rx_disposeBag) store.error .subscribe(onNext: { error in ErrorAction.show(.apiError(error)) }) .addDisposableTo(rx_disposeBag) store.someModel.asObservable() .map { $0.dataSource } .observeOn(MainScheduler.instance) .subscribe(onNext: { [unowned self] dataSource in self.dataSource.value = dataSource self.tableView?.reloadData() }) .addDisposableTo(rx_disposeBag) ErrorActionΛ࣮ߦ
View store.loading.asObservable() .distinctUntilChanged() .observeOn(MainScheduler.instance) .subscribe(onNext: { [unowned self] loading in
self.loadingView.hidden(!loading) }) .addDisposableTo(rx_disposeBag) store.error .subscribe(onNext: { error in ErrorAction.show(.apiError(error)) }) .addDisposableTo(rx_disposeBag) store.someModel.asObservable() .map { $0.dataSource } .observeOn(MainScheduler.instance) .subscribe(onNext: { [unowned self] dataSource in self.dataSource.value = dataSource self.tableView?.reloadData() }) .addDisposableTo(rx_disposeBag) StoreͷsomeModelΛobserve
View store.loading.asObservable() .distinctUntilChanged() .observeOn(MainScheduler.instance) .subscribe(onNext: { [unowned self] loading in
self.loadingView.hidden(!loading) }) .addDisposableTo(rx_disposeBag) store.error .subscribe(onNext: { error in ErrorAction.show(.apiError(error)) }) .addDisposableTo(rx_disposeBag) store.someModel.asObservable() .map { $0.dataSource } .observeOn(MainScheduler.instance) .subscribe(onNext: { [unowned self] dataSource in self.dataSource.value = dataSource self.tableView?.reloadData() }) .addDisposableTo(rx_disposeBag) tableViewΛreload
View searchBar.rx.text.asDriver() .throttle(0.3) .distinctUntilChanged() .drive(onNext: { query in SomeAction.someAction(query: query)
}) .addDisposableTo(rx_disposeBag) UIͷeventΛobserve
View searchBar.rx.text.asDriver() .throttle(0.3) .distinctUntilChanged() .drive(onNext: { query in SomeAction.someAction(query: query)
}) .addDisposableTo(rx_disposeBag) searchBarͷtextೖྗΛobserve
View searchBar.rx.text.asDriver() .throttle(0.3) .distinctUntilChanged() .drive(onNext: { query in SomeAction.someAction(query: query)
}) .addDisposableTo(rx_disposeBag) ೖྗ͞Εͨจࣈʹมߋ͕͋ΔຖʹActionΛ࣮ߦ
Flux with RxSwift Action Dispatcher User Interactions API DB ViewController
View Store Events Events
Ұप͠·ͨ͠ʂ Flux with RxSwift
Proposals
Proposals • DispatcherҰͭʹ͍ͨ͠ • StoreSingletonͰͳ͘ɺదͳϥΠϑαΠ Ϋϧʹ͍ͨ͠ • StoreΛread-onlyʹ͍ͨ͠
Conclusion
Conclusion Pros • ෳͷViewController, ViewΛͬͯෳࡶͳঢ়ଶ ཧΛ͢ΔΞϓϦέʔγϣϯʹ͍͍ͯΔ • ։ൃऀͷ࣮͕౷Ұ͞Ε͍͢ • Viewؒͷґଘ͕ؔݮΔ
Conclusion Cons • SingletonͰूதཧͳͷͰɺ͖ݏ͍͋Δ͔ • ׳ΕΔ·Ͱগ͔͔͠Δ • ࣮͕ʹײ͡Δ…?
FluxΈͳͷͰɺΑΓྑ͘͢ΔͨΊʹ νʔϜͰTrial&Errorͯ͠·͢ Flux with RxSwift
Thank you ࢀߟࢿྉ https://facebook.github.io/flux/ https://github.com/facebook/flux https://github.com/thoughtbot/Delta https://github.com/yonekawa/SwiftFlux https://speakerdeck.com/ogaclejapan/flux-de-relax
https://github.com/dekatotoro/FluxWithRxSwiftSample Flux with RxSwift Sample