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
Hello, ReactorKit ๐
Search
Suyeol Jeon
June 28, 2018
Programming
120
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Hello, ReactorKitย ๐
https://www.slideshare.net/devxoul/hello-reactorkit
Suyeol Jeon
June 28, 2018
More Decks by Suyeol Jeon
See All by Suyeol Jeon
แแ ฅแผแแ กแผแแ กแแ ณแซ iOS แแ ขแแ กแฏแแ ก แแ ฌแแ ต
devxoul
2
260
แ แ ฆแแ ฅแแ ต แแ ณแ แ ฉแแ ฆแจแแ ณแแ ฆแแ ฅ แแ ดแแ ฉแซแแ ฅแผ แแ ฎแแ ตแธแแ กแแ ต
devxoul
1
2.6k
Let's TDD
devxoul
0
110
Build Funnels with Google BigQuery
devxoul
0
73
RxSwift แแ ตแแ กแจแแ กแแ ต
devxoul
1
370
ReactorKit์ผ๋ก ๋จ๋ฐฉํฅ ๋ฐ์ํ ์ฑ ๋ง๋ค๊ธฐ
devxoul
0
190
Swift - ํผ์ ๊ณต๋ถํ๋ฉด ๋ถ๋ช ํ ์ํ ํ ๋๊น ๊ฐ์ด ๊ณต๋ถํ๊ธฐ
devxoul
10
3.3k
แแ ฉแแแ ณแซ แแ ตแแ กแแ ตแแ ฅ, แแ กแแ ณแซ แแ ณแ แ ฉแแ ฆแจแแ ณแแ ขแแ ตแแ ฅ, แแ ตแแ กแผแแ กแซ แแ ขแแ กแฏแแ ก
devxoul
0
130
Other Decks in Programming
See All in Programming
ๅ่งฃๆใงๅฎ็พใใ Go ใฎ่จ่ชๅ DSL / Conference ใซ Go! ใฟใคใ ใใผใใซใฎๆญฉใๆน for Gophers
mazrean
0
130
ใDroidKaigi 2026ใใใขใฏใปใทใใชใใฃใๅฉ็จใใใจใใ ใขใฏใปใทใใชใใฃใใพใใใกใใๅฉ็จใใฆใใใ ใใใซใฆใงใขใซใใๆปๆใจ้ฒ่กใซใคใใฆใ
halunoyo
0
400
AI ใซ Inclusive UI ใๆธใใใใ โ Design Rules Skill ใง Compose UI ใไฝใ็ดใ
theoriatec2024
1
450
Laravelใฎใขใใชใฑใผใทใงใณใใฉใใซใใใญใคใใใ #ใใใฎใกใชใใฉใคใณ.9
akase244
0
120
AI้งๅ้็บใซใฏใใฉใDBใ้ใญใฆใฟใ
satoshi256kbyte
2
740
Discordใ็จใใใฉใใชใผใใกใผใทใงใณ้ข้ฃๆ ๅ ฑๅ้ใฎ่ชๅๅ
noguhiro2002
0
500
Seeing Through Serverless: Observability for AWS Lambda with ADOT and CloudWatch Application Signals
seike460
PRO
1
120
ALB ใญใฐใใ Trace ใๆฐๅใง็นใใๆ่ก
fohte
7
870
AIใฎไธญใฎไบบใซใชใฃใฆใฟใ
htkym
0
170
ไธๅๅ ่ ใใใไธญใฎไบบใใธ ใๅ จ้PHPerใใใผในใซ็ซใฃใฆๅญฆใใ ใใซใณใใกใฌใณในใ100ๅๆฅฝใใใณใใ
wp_daisuke
0
120
ใฌใใฅใผๅฑฅๆญดใAIใซ้ฃใใใฆใ Compose็งป่กใๅ ้ใใs
shihochan
0
270
ใฝใใใฆใงใขใฉในใฟใฉใคใถ
fadis
1
790
Featured
See All Featured
Side Projects
sachag
455
43k
Building the Perfect Custom Keyboard
takai
2
860
Automating Front-end Workflow
addyosmani
1369
210k
What's in a price? How to price your products and services
michaelherold
247
13k
Why You Should Never Use an ORM
jnunemaker
PRO
61
10k
YesSQL, Process and Tooling at Scale
rocio
174
15k
The agentic SEO stack - context over prompts
schlessera
0
900
Un-Boring Meetings
codingconduct
0
410
My Coaching Mixtape
mlcsv
0
310
StorybookใฎUI Testing Handbookใ่ชญใใ
zakiyama
31
6.9k
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
920
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.6k
Transcript
Hello, ReactorKit! Suyeol Jeon https://github.com/devxoul
Jeon Suyeol StyleShare Inc. Open Source Lover Then URLNavigator RxSwift
ObjectMapper
Why?
Why? Massive View Controller
Why? Massive View Controller RxSwift State Managing
Massive View Controller https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/MVC.html
Massive View Controller https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/MVC.html
Massive View Controller https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/MVC.html
RxSwift State Managing Cyclic Data Dependencies
RxSwift State Managing currentValue increaseValue()
RxSwift State Managing currentValue increaseValue() last state
RxSwift State Managing currentValue increaseValue() last state result
RxSwift State Managing Cyclic Data Dependencies
RxSwift State Managing Cyclic Data Dependencies Pagination List operation Value
update ...
RxSwift State Managing After a while...
RxSwift State Managing After a while... Variable<Int> PublishSubject<Int> PublishRelay<[Item]> Variable<User>
BehaviorSubject<String> Variable<String>
I wanted to... 1. Avoid Massive View Controller
I wanted to... 1. Avoid Massive View Controller 2. Take
advantages of RxSwift
I wanted to... 1. Avoid Massive View Controller 2. Take
advantages of RxSwift 3. Manage states gracefully
ReactorKit
ReactorKit can... 1. Avoid Massive View Controller โ
ReactorKit can... 1. Avoid Massive View Controller โ Separates responsibilities
of view and logic
ReactorKit can... 1. Avoid Massive View Controller โ Separates responsibilities
of view and logic View Controller becomes simple
ReactorKit can... 2. Take advantages of RxSwift โ
ReactorKit can... 2. Take advantages of RxSwift โ Based on
RxSwift
ReactorKit can... 2. Take advantages of RxSwift โ Based on
RxSwift All of RxSwift features are available
ReactorKit can... 3. Manage states gracefully โ
ReactorKit can... 3. Manage states gracefully โ Unidirectional data flow
ReactorKit can... 3. Manage states gracefully โ Unidirectional data flow
Modify states only in reduce()
ReactorKit can... 3. Manage states gracefully โ Unidirectional data flow
Modify states only in reduce() State management became easy
ReactorKit can... Be the future ~1.1K โญ ~50K downloads ~900
apps https://starcharts.herokuapp.com/ReactorKit/ReactorKit
ReactorKit can... Be the future ~1.1K โญ ~50K downloads ~900
apps https://starcharts.herokuapp.com/ReactorKit/ReactorKit
Basic Concept
Basic Concept Abstraction of User Interaction Abstraction of View State
Basic Concept Renders view states Handles user interactions ViewController, Cell,
...
Basic Concept protocol View { associatedtype Reactor var disposeBag: DisposeBag
// gets called when // self.reactor is changed func bind(reactor: Reactor) }
Basic Concept protocol StoryboardView { associatedtype Reactor var disposeBag: DisposeBag
// gets called when // the view is loaded func bind(reactor: Reactor) } // for Storyboard support
Basic Concept Performs business logic Manages states Corresponds to view
Basic Concept protocol Reactor { associatedtype Action associatedtype Mutation associatedtype
State var initialState: State }
Basic Concept Based on RxSwift
Data Flow
Data Flow
Data Flow Action โ State โ
Data Flow Action โ Mutation โ State
Data Flow Action โ Mutation โ State State manipulator
Data Flow State manipulator Async-able Action โ Mutation โ State
Data Flow State manipulator Async-able Not exposed to view Action
โ Mutation โ State
Data Flow (Action) -> Observable<Mutation> (State, Mutation) -> State
Data Flow
Data Flow class ProfileViewReactor: Reactor { enum Action { }
struct State { } }
Data Flow class ProfileViewReactor: Reactor { enum Action { case
follow // user interaction } struct State { } }
Data Flow class ProfileViewReactor: Reactor { enum Action { case
follow // user interaction } struct State { var isFollowing: Bool // view state } }
Data Flow class ProfileViewReactor: Reactor { enum Action { case
follow // user interaction } struct State { var isFollowing: Bool // view state } } Execute user follow API โ Change state
Data Flow class ProfileViewReactor: Reactor { enum Action { case
follow // user interaction } struct State { var isFollowing: Bool // view state } } Execute user follow API โ Change state Async
Data Flow class ProfileViewReactor: Reactor { enum Action { case
follow // user interaction } enum Mutation { } struct State { var isFollowing: Bool // view state } }
Data Flow class ProfileViewReactor: Reactor { enum Action { case
follow // user interaction } enum Mutation { case setFollowing(Bool) // change state } struct State { var isFollowing: Bool // view state } }
Data Flow
Data Flow Tap follow button
Data Flow Action.follow
Data Flow Action.follow
Data Flow UserService.follow()
Data Flow UserService
Data Flow Observable<Bool>
Data Flow
Data Flow Mutation.setFollowing(true)
Data Flow Mutation.setFollowing(true)
Data Flow isFollowing = true
Data Flow Update follow button
Data Flow
More Examples
More Examples
Advanced View Communications Testing View and Reactor
View Communications ProfileViewController ProfileViewReactor
View Communications UICollectionView ProfileViewController ProfileViewReactor
View Communications UICollectionView ProfileViewController ProfileViewReactor UserCell
View Communications Passing user data Observing button tap
View Communications - Passing user data ProfileView Controller UserCell ProfileView
Reactor
View Communications - Passing user data ProfileView Controller UserCell ProfileView
Reactor 1. User
View Communications - Passing user data ProfileView Controller UserCell ProfileView
Reactor 1. User 2. User
View Communications - Passing user data // ProfileViewReactor struct State
{ }
View Communications - Passing user data // ProfileViewReactor struct State
{ var user: User? }
View Communications - Passing user data // ProfileViewReactor struct State
{ var user: User? } // ProfileViewController let cell = collectionView.dequeue... return cell
View Communications - Passing user data // ProfileViewReactor struct State
{ var user: User? } // ProfileViewController let cell = collectionView.dequeue... if let reactor = self.reactor { } return cell
View Communications - Passing user data // ProfileViewReactor struct State
{ var user: User? } // ProfileViewController let cell = collectionView.dequeue... if let reactor = self.reactor { cell.user = reactor.currentState.user } return cell
View Communications - Observing button tap ProfileView Controller UserCell ProfileView
Reactor
View Communications - Observing button tap ProfileView Controller UserCell ProfileView
Reactor 1. rx.tap
View Communications - Observing button tap ProfileView Controller UserCell ProfileView
Reactor 2. Action.follow 1. rx.tap
View Communications - Observing button tap ProfileView Controller UserCell ProfileView
Reactor 2. Action.follow 1. rx.tap Reactive Extension
View Communications - Observing button tap // UserCell extension Reactive
where Base: UserCell { }
View Communications - Observing button tap // UserCell extension Reactive
where Base: UserCell { var buttonTap: ControlEvent<Void> { } }
View Communications - Observing button tap // UserCell extension Reactive
where Base: UserCell { var buttonTap: ControlEvent<Void> { return self.base.followButton.rx.tap } }
View Communications - Observing button tap // UserCell extension Reactive
where Base: UserCell { var buttonTap: ControlEvent<Void> { return self.base.followButton.rx.tap } } // ProfileViewController cell.user = reactor.currentState.user
View Communications - Observing button tap // UserCell extension Reactive
where Base: UserCell { var buttonTap: ControlEvent<Void> { return self.base.followButton.rx.tap } } // ProfileViewController cell.user = reactor.currentState.user cell.rx.buttonTap
View Communications - Observing button tap // UserCell extension Reactive
where Base: UserCell { var tap: ControlEvent<Void> { return self.base.followButton.rx.tap } } // ProfileViewController cell.user = reactor.currentState.user cell.rx.buttonTap .map { Reactor.Action.follow }
View Communications - Observing button tap // UserCell extension Reactive
where Base: UserCell { var tap: ControlEvent<Void> { return self.base.followButton.rx.tap } } // ProfileViewController cell.user = reactor.currentState.user cell.rx.buttonTap .map { Reactor.Action.follow } .bind(to: reactor.action)
View Communications - Observing button tap // UserCell extension Reactive
where Base: UserCell { var tap: ControlEvent<Void> { return self.base.followButton.rx.tap } } // ProfileViewController cell.user = reactor.currentState.user cell.rx.buttonTap .map { Reactor.Action.follow } .bind(to: reactor.action) .disposed(by: self.disposeBag)
View Communications UICollectionView ProfileViewController ProfileViewReactor UserCell
View Communications UICollectionView ProfileViewController ProfileViewReactor UserCell UserCellReactor
View Communications - Passing user data ProfileView Controller UserCell ProfileView
Reactor
View Communications - Passing user data ProfileView Controller UserCell ProfileView
Reactor UserCell Reactor
View Communications - Passing user data ProfileView Controller UserCell ProfileView
Reactor 1. CellReactor UserCell Reactor
View Communications - Passing user data ProfileView Controller UserCell ProfileView
Reactor 1. CellReactor 2. CellReactor UserCell Reactor
View Communications - Passing user data ProfileView Controller UserCell ProfileView
Reactor 1. CellReactor 2. CellReactor UserCell Reactor
View Communications - Passing user data // ProfileViewReactor struct State
{ var user: User? }
View Communications - Passing user data // ProfileViewReactor struct State
{ var user: User? var userCellReactor: UserCellReactor? }
View Communications - Passing user data // ProfileViewReactor struct State
{ var user: User? var userCellReactor: UserCellReactor? } // ProfileViewController cell.user = reactor.currentState.user
View Communications - Passing user data // ProfileViewReactor struct State
{ var user: User? var userCellReactor: UserCellReactor? } // ProfileViewController cell.user = reactor.currentState.user cell.reactor = reactor.currentState.userCellReactor
Testing View and Reactor What to test? View Reactor
Testing View and Reactor What to test? View Action: on
user interaction โ action sent? Reactor
Testing View and Reactor What to test? View Action: on
user interaction โ action sent? State: on state change โ view updated? Reactor
Testing View and Reactor What to test? View Action: on
user interaction โ action sent? State: on state change โ view updated? Reactor State: on action receive โ state updated?
Testing View and Reactor How to test?
Testing View and Reactor How to test? Reactor.stub()
Testing View and Reactor How to test? Reactor.stub() state: set
fake state
Testing View and Reactor How to test? Reactor.stub() state: set
fake state action: send fake action
Testing View and Reactor How to test? Reactor.stub() state: set
fake state action: send fake action actions: log received actions
Testing View and Reactor - View Action
Testing View and Reactor - View Action When: follow button
taps Then: sends follow action
Testing View and Reactor - View Action // given let
reactor = ProfileViewReactor() // when // then
Testing View and Reactor - View Action // given let
reactor = ProfileViewReactor() reactor.stub.isEnabled = true // when // then
Testing View and Reactor - View Action // given let
reactor = ProfileViewReactor() reactor.stub.isEnabled = true reactor.stub.state.value.user = User() // when // then
Testing View and Reactor - View Action // given let
reactor = ProfileViewReactor() reactor.stub.isEnabled = true reactor.stub.state.value.user = User() let viewController = ProfileViewController() viewController.reactor = reactor // when // then
Testing View and Reactor - View Action // given let
reactor = ProfileViewReactor() reactor.stub.isEnabled = true reactor.stub.state.value.user = User() let viewController = ProfileViewController() viewController.reactor = reactor // when let button = viewController.userCell.followButton // then
Testing View and Reactor - View Action // given let
reactor = ProfileViewReactor() reactor.stub.isEnabled = true reactor.stub.state.value.user = User() let viewController = ProfileViewController() viewController.reactor = reactor // when let button = viewController.userCell.followButton button.sendActions(for: .touchUpInside) // then
Testing View and Reactor - View Action // given let
reactor = ProfileViewReactor() reactor.stub.isEnabled = true reactor.stub.state.value.user = User() let viewController = ProfileViewController() viewController.reactor = reactor // when let button = viewController.userCell.followButton button.sendActions(for: .touchUpInside) // then let lastAction = reactor.stub.actions.last XCTAssertEqual(lastAction, .follow)
Testing View and Reactor - View State When: following the
user Then: button is selected
Testing View and Reactor - View State // given let
cellReactor = UserCellReactor() // when // then
Testing View and Reactor - View State // given let
cellReactor = UserCellReactor() cellReactor.stub.isEnabled = true // when // then
Testing View and Reactor - View State // given let
cellReactor = UserCellReactor() cellReactor.stub.isEnabled = true let cell = UserCell() cell.reactor = cellReactor // when // then
Testing View and Reactor - View State // given let
cellReactor = UserCellReactor() cellReactor.stub.isEnabled = true let cell = UserCell() cell.reactor = cellReactor // when cellReactor.stub.state.value.isFollowing = true // then
Testing View and Reactor - View State // given let
cellReactor = UserCellReactor() cellReactor.stub.isEnabled = true let cell = UserCell() cell.reactor = cellReactor // when cellReactor.stub.state.value.isFollowing = true // then XCTAssertTrue(cell.followButton.isSelected)
Testing View and Reactor - Reactor State When: receive follow
action Then: update following state ProfileView Reactor
Testing View and Reactor - Reactor State // given let
reactor = ProfileViewReactor() // when // then
Testing View and Reactor - Reactor State // given let
reactor = ProfileViewReactor() // when reactor.action.onNext(.follow) // then
Testing View and Reactor - Reactor State // given let
reactor = ProfileViewReactor() // when reactor.action.onNext(.follow) // then let user = reactor.currentState.user XCTAssertEqual(user?.isFollowing, true)
Future Ideas Development Documentation Community
Development Testing Support SectionReactor AlertReactor ModelReactor Plugins ... Nested stub
Dummy reactor ... Building Extensions
Documentation Best Practices Translations Code-level Documentation
Community RxSwift Slack #reactorkit (English) https://rxswift-slack.herokuapp.com Swift Korea Slack #reactorkit
(Korean) http://slack.swiftkorea.org
https://reactorkit.io