Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- ribs
- 스위프트
- clean architecture
- collectionview
- 애니메이션
- Xcode
- SWIFT
- 클린 코드
- UITextView
- 리펙터링
- swiftUI
- Clean Code
- tableView
- UICollectionView
- Protocol
- 리팩토링
- combine
- Observable
- uiscrollview
- HIG
- uitableview
- Refactoring
- 리펙토링
- Human interface guide
- MVVM
- map
- swift documentation
- rxswift
- RxCocoa
- ios
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] 1. ReactorKit - 개념 본문
1. ReactorKit - 개념
2. ReactorKit - 테스트 방법 (Storyboard 사용, IBOutlet 테스트 방법)
3. ReactorKit - `TaskList 구현`, 템플릿 (template), 비동기 처리 transform(mutation:)
4. ReactorKit - `TaskEdit 구현`, 화면전환, 데이터 전달
* 해당 코드는 ReactorKit git repository 코드를 참고하였습니다.
ReactorKit 개념
- RxSwift의 강점인 비동기 처리에 편리한 코드
- API를 통해 앱에서 연속적인 페이지 로드할 때 이전 페이지를 기록해놓아야 하듯이, 이전 페이지를 기록하는 `상태`컴포넌트가 따로 관리되게끔 설계된 구조
- `상태`라는 컴포넌트 추상화 개념이 적용되어 있고, 컴포넌트 간 결합도가 낮기 때문에 테스트하기에 용이한 구조
- MVVM과 같은 아키텍처는 규격화된게 없어서 개발자, 회사마다 모두 달라 일관적이지 않은 반면에 ReactorKit은 형식이 갖추어진 형태
CocoaPods
pod 'ReactorKit'
pod 'RxCocoa'
컴포넌트
- UI에 해당하는 View와 UI에 반응하여 비즈니스 로직을 처리하는 Reactor로 구성
- Reactor에 View의 Action을 미리 정의해놓고, 해당 action을 처리하여 다시 View에 State값을 넘기는 것
- View에서는 인터렉터 이벤트들을 Reactor의 Action값으로 넘기고, reactor의 state값을 구독하고 UI업데이트 하는 것
View
- UI가 있고, UI들의 action을 reactor에 넘기고, reactor의 state를 구독하고 있는 형태
ex) increaseButton 예시
- ReactorKit 내부적으로 호출되는 bind(reactor:) 메소드에서 바인딩 수행
- bindAction(_:): View에서 Reactor로 이벤트 방출
- bindState(_:): Reactor에서 바뀐 state들을 View에서 구독
- storyboard 이용 시 StoryboardView 구현
import UIKit
import RxSwift
import RxCocoa
import ReactorKit
class CounterViewController: UIViewController, StoryboardView {
var disposeBag = DisposeBag()
@IBOutlet weak var countLabel: UILabel!
@IBOutlet weak var increaseButton: UIButton!
func bind(reactor: CounterViewReactor) {
bindAction(reactor)
bindState(reactor)
}
private func bindAction(_ reactor: CounterViewReactor) {
increaseButton.rx.tap
.map { Reactor.Action.increase }
.bind(to: reactor.action)
.disposed(by: disposeBag)
}
private func bindState(_ reactor: CounterViewReactor) {
reactor.state
.map { String($0.value) }
.distinctUntilChanged()
.bind(to: countLabel.rx.text)
.disposed(by: disposeBag)
}
}
Reactor
- Action
- View로부터 받을 Action을 enum으로 정의
- Mutation
- View로부터 action을 받은 경우, 해야할 작업단위들을 enum으로 정의
- State
- 현재 상태를 기록하고 있으며, View에서 해당 정보를 사용하여 UI업데이트 및 Reactor에서 image를 얻어올때 page정보들을 저장
- mutate(action:) -> Observable<Mutation>
- Action이 들어온 경우, 어떤 처리를 할것인지 Mutation에서 정의한 작업 단위들을 사용하여 Observable로 방출
- 해당 부분에서, RxSwift의 concat 연산자를 이용하여 비동기 처리가 유용
- concat 연산자: 여러 Observable이 배열로 주어지면 순서대로 실행
(이 밖의 merge, combineLatest, withLatestFrom, zip 사용 개념 참고)
- reduce(state:mutation:) -> State
- 현재 상태(state)와 작업 단위(mutation)을 받아서, 최종 상태를 반환
- mutate(action:) -> Observable<Mutation>이 실행된 후 바로 해당 메소드 실행
import Foundation
import RxSwift
import RxCocoa
import ReactorKit
class CounterViewReactor: Reactor {
let initialState = State()
enum Action {
case increase
case decrease
}
// 처리 단위
enum Mutation {
case increaseValue
case decreaseValue
case setLoading(Bool)
}
// 현재 상태를 기록
struct State {
var value = 0
var isLoading = false
}
// Action이 들어온 경우, 어떤 처리를 할건지 분기
func mutate(action: Action) -> Observable<Mutation> {
switch action {
case .increase:
return Observable.concat([
Observable.just(.setLoading(true)),
Observable.just(.increaseValue).delay(.seconds(1), scheduler: MainScheduler.instance),
Observable.just(.setLoading(false))
])
case .decrease:
return Observable.concat([
Observable.just(.setLoading(true)),
Observable.just(.decreaseValue).delay(.seconds(1), scheduler: MainScheduler.instance),
Observable.just(.setLoading(false))
])
}
}
// 이전 상태와 처리 단위를 받아서 다음 상태를 반환하는 함수
func reduce(state: State, mutation: Mutation) -> State {
var newState = state
switch mutation {
case .increaseValue:
newState.value += 1
case .decreaseValue:
newState.value -= 1
case .setLoading(let isLoading):
newState.isLoading = isLoading
}
return newState
}
}
* 전체 소스 코드: https://github.com/JK0369/ExReactorKit/tree/BaseComponent
* 참고
- https://medium.com/styleshare/reactorkit-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-c7b52fbb131a
'Architecture (swift) > ReactorKit' 카테고리의 다른 글
Comments