Workspace X 앱을 구성할 때, TCA 를 사용하여 앱을 제작했는데
Reducer 패턴을 적용한 TCA 를 좀 더 이해하기 위해
Reducer 패턴이란 무엇인가를 주제로 글을 쓰게 되었습니다.
리듀서 패턴
을 배우기 전, 리듀서가 무엇인지 알아야 할듯합니다.
Reducer란?
함수형 프로그래밍에서 유래된 개념으로 상태(State)와 액션(Action)을 받아서 새로운 상태를 반환하는 함수이다.
라고 되어 있는데요 이해를 위해 iOS의 기본 패턴인 MVC 를 다시 살펴보도록 하겠습니다.
View에서 이벤트가 발생하면 Controller에 알리고
Controller가 이벤트를 처리하면 Model에 업데이트를 명령합니다.
Model은 업데이트한 후 컨트롤러에 알린 후 컨트롤러는 이를 View에 알리는 구조였죠
MVC 패턴의 장점은 유연성과 양방향성이었습니다.
단점으론 코드가 방대해지고, 체인 형식으로 업데이트가 이루어져 그 경로를 찾기 어려워지는 구조였습니다.
다시 Reducer란 이 "이전 상태와 동작을 받아 새 상태를 리턴하는 순수 함수를 말합니다."
순수 함수
란 같은 인자가 들어오면 항상 같은 값이 나와야 하며, return 값으로만 소통하고 데이터
베이스 혹은 네트워크 호출등 외부의 데이터 구조를 변형하는 호출을 허용하지 않는 함수를 말합니다.
App의 상태 관리를 위해 리듀서 함수를 통해 상태 변화를 정의하는 디자인 패턴입니다.
단반향 데이터 흐름을 기반으로 합니다.
App의 현재 상태를 나타내는 구조체 입니다.
struct ExState: Equatable { var counter: Int = 0 }
상태를 변경하기위한 이벤트 정의
enum ExAction { case increment(amount: Int) case decrement(amount: Int) }
현재 상태와 액션을 받아서 새로운 상태를 반환하는 순수함수
func ExReducer(state: inout AppState, action: AppAction) { switch action { case .increment(let amount): state.counter += amount case .decrement(let amount): state.counter -= amount } }
상태와 리듀서를 포함하고 상태를 업데이트
class Store: ObservableObject {
@Published private(set) var state: AppState
private let reducer: (inout ExState, ExAction) -> Void
init(initialState: AppState, reducer: @escaping (inout ExState, ExAction) -> Void) {
self.state = initialState
self.reducer = reducer
}
func dispatch(action: AppAction) {
reducer(&state, action)
}
}
### 사용시
ContentView(store: Store(initialState: ExState(), reducer: ExReducer))
store.dispatch(action: .increment(amount: 1))
상당히 흥미로운 패턴을 다루어본 것 같습니다.
블로그 작성이 늦어 져서 죄송합니다. ㅠㅠ 과제하느라 작성을 못했었네요 ㅠㅠ
오늘 하루도 모두 고생하였습니다!