티스토리 뷰
iOS TCA, 이벤트 발생 시 Action, State, Reducer 동작과정
applebuddy 2022. 10. 11. 22:51
TCA는 Point-free에서 제안한 아키텍쳐로 The Composable Architecture라고 하며, Store의 State 변화에 따라 View를 업데이트해주는 상태 기반의 단방향 아키텍쳐입니다.
저는 개인적으로 개발한 앱에 TCA를 도입하여 사용하고 있습니다. 또한 화면 전환 이벤트를 편리하게 관리하기 위해 TCACoordinator를 함께 사용하여 개발하고 있습니다.
오늘은 제가 개발한 코드 일부를 보면서 TCA의 간략한 동작 방식을 돌아보고자 합니다. 최상위 뷰부터 해서 순차적으로 그림을 그려보는 것보다는 하위 뷰의 단편적인 이벤트 발생을 기점으로 TCA의 동작방식을 돌아보려고 합니다. 언제든 포스팅 내용에 대한 피드백 부탁드립니다.
TCA에서 각각의 View는 Store를 갖는다.
TCA에서는 MVVM 디자인패턴을 적용할때 처럼 ObservableObject 프로토콜을 채용한 ViewModel을 구현하고, @ObservedObject, @StateObject로 가져와서 사용하는 방식을 취하지 않습니다.
각각의 View는 저마다의 Store를 갖고 있습니다. Store가 갖는 State는 각각의 View에 대한 비즈니스로직 및 설명에 필요한 데이터가 정의되고, Action에는 이벤트가 enum 타입으로 정의 됩니다. State, Action, Reducer (+ Environment)들은 각각의 View에 대응되는 Core 파일에 정의가 됩니다.
Store는 사용자가 특정 Action을 보낼때마다 내부의 reducer에서 State 값을 변경하고 다음 이벤트를 실행한 Effect를 반환할 수 있습니다. 그리고 변경된 State에 맞게 View를 업데이트 시킬 수 있습니다.
WithViewStore를 통해 Store를 ObservableObject 프로토콜을 채택한 ViewStore로 변환
각각의 View body 블럭 내부에는 WithViewStore로 감싸여있습니다. WithViewStore는 store를 ObservableObject 프로토콜을 준수하는 viewStore로 변환하여 View를 계산하는데에 사용합니다. State가 변경되면 그에 맞게 View가 업데이트 되는데, State가 변경되기 위해서는 특정 이벤트를 감지해야합니다. 어떻게 이벤트를 받는지 보겠습니다.
ViewStore를 통해 필요할때 특정 Action을 전송
위 코드는 특정 버튼을 눌렀을때 reconnectWebSocket 이벤트를 전송하는 모습입니다. viewStore.send(_:)를 통해 특정 이벤트를 전송하며, reducer는 해당 이벤트에 맞는 동작을 실행합니다.
이러한 View에서 발생될 수 있는 Action들은 enum 타입으로 정의가 됩니다. Reducer는 이러한 Action들을 발생하는 case에 맞게 처리합니다.
Reducer에서 Action에 맞게 State를 변경하고, 다음 이벤트를 실행할 Effect를 반환
ViewStore에서 send를 통해 특정 Action을 전송하면 Reducer는 Action에 맞는 동작을 실행합니다. Reducer는 발생한 Action 이벤트에 맞게 State를 바꾸거나 추가적인 이벤트를 Effect 타입으로 반환할 수 있습니다. 이때 반환하는 Effect는 Combine framework의 Publisher타입이며, Effect는 다양한 Combine Operator기능을 래핑한 연산자 메서드를 지원하고 있습니다.
위 코드는 보시면 .onAppear 이벤트가 발생했을때 Effect의 concatenate 래핑 연산자를 통해 다양한 Effect들을 순차적으로 실행하는 것을 보실 수 있습니다.
위 코드는 Effect의 생성자 중 하나입니다. 하나의 이벤트를 Just로 즉시 방출하고 있습니다. 만약 특정 이벤트가 실행되고 추가적인 이벤트 발생을 원치 않는다면 어떻게 해야할까요?
이어서 실행할 이벤트가 없을때?
위 코드는 Effect에 구현되어 있는 타입 프로퍼티 입니다. 더이상 수행할 Action이 없다면, .none을 반환하면 됩니다.
위와 같이 특정 이벤트에 맞게 state 멤버 변수를 수정할 수 있습니다. 근데 그 다음 추가적인 이벤트를 실행할 생각이 없다면? .none을 반환하면 됩니다.
이렇게 Action이 전송되면, Reducer는 Action case에 맞는 작업을 수행하며 이때 state 멤버변수를 변경하거나 또다른 Effect 들을 반환할 수 있었습니다.
+ 분해, 결합이 가능한 Reducer
local하게, 때로는 global하게 사용될 수 있다.
지금까지 봤듯이 Reducer는 이벤트에 맞게 State를 변경하고 그 다음의 Effect를 반환하는데요. 이런 Reducer는 여러개가 있을 수 있습니다. 최상단의 AppReducer부터 시작해서, MainReducer, AReducer, BReducer, CReducer... 같이 말이죠.
이러한 Reducer들은 서로 분해하고 결합할 수 있습니다. pullback을 통해 다양한 기능 화면의 reducer들이 local -> global하게 사용될 수 있도록 변경하고, combine으로 하나의 reducer로 결합할 수 있습니다. 위에서 사용된 combine 메서드를 보겠습니다.
Reducer는 combine 타입 메서드를 통해 다수의 reducer들을 가변인자로 받아서 하나의 reducer로 변환할 수 있는 것을 볼 수 있습니다.
TCA에서 Action을 통해 State를 바꾸고, Effect를 반환하며, 그에 맞게 View를 업데이트하는 동작과정을 한번 돌아봤습니다. 이렇게 TCA Architecture 상에서 각 View들은 Store의 상태에 맞게 업데이트되고 액션을 처리합니다.
그리고 각 Store에서 동작하는 Reducer들은 필요에 따라 결합되고 분해될 수 있으며, local reducer를 pullback을 통해 global하게 사용가능한 reducer로 만들어서 하위 reducer를 상위 reducer에서 관리할 수도 있습니다.
추가적으로 TCA의 Effect Publisher 구독 및 구독해지 방식이 궁금하시면 아래 포스팅 참고하시고 많은 의견 부탁드립니다. 감사합니다.
'iOS 개발 > SwiftUI, Combine' 카테고리의 다른 글
TCA, ViewStore Action 전송 간 Effect 구독과 메모리해제 동작방식 (0) | 2022.10.26 |
---|---|
SwiftUI, ViewModifier로 Custom NavigationBar 만드는 방법 (0) | 2022.10.13 |
SwiftUI View에 Publisher로 키보드 show, hide 이벤트 처리방법 (0) | 2022.10.03 |
RxSwift Observable, 연산자를 사용한 API 요청 및 UI 바인딩 방법 (0) | 2022.09.30 |
Combine Publisher, 연산자로 키보드검색, API 요청, 응답 처리방법 (0) | 2022.09.29 |
- Total
- Today
- Yesterday
- swift문제
- 컬렉션
- swift 문자열
- 스위프트
- SwiftUI
- 부스트코스
- createML
- 프로토콜
- swift
- swift reduce
- 자연어처리
- swift 기초
- Protocol
- uikit
- 알고리즘
- swift알고리즘
- CoreML
- 백준알고리즘
- Swift 알고리즘
- swift string
- 알고리즘문제
- 프로그래머스swift
- 김프매매
- publisher
- ios
- 프로그래머스
- 백준swift
- Collection
- swift언어
- 개발자문서
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |