iOS

[iOS] [SwiftUI] [TCA] TCA에 대해 알아보고 간단한 튜토리얼을 완료해보자

sujileelea 2023. 12. 16. 16:18
공식 github
 

GitHub - pointfreeco/swift-composable-architecture: A library for building applications in a consistent and understandable way,

A library for building applications in a consistent and understandable way, with composition, testing, and ergonomics in mind. - GitHub - pointfreeco/swift-composable-architecture: A library for bu...

github.com

 

개요

기존에는 MVVM 아키텍처 패턴을 사용했으나, 구현해야할 기능이 늘어나면서 과연 ViewModel이 코드를 작성하는데 도움이 되는가 하는 의문이 생겼다.
비즈니스 로직이 담기는 만큼 ViewModel의 규모가 커지고, 같은 데이터를 뷰와 뷰 모델 양쪽에서 접근하고 제어할 수 있다는 점에도 의문이 들었다. View에서 @State@Binding 프로퍼티 래퍼를 사용해 데이터에 접근할 수 있는데 굳이 ViewModel을 거쳐서...?
SwiftUI가 지향하는 데이터의 단방향 플로우와는 사뭇 다르다.

 

MVVM vs TCA 작동 방식 비교

MVVM 작동 방식

그렇다고 View에 모든 로직을 다 작성한다면 View가 복잡해지고 방대해질 뿐더러, 비록 화면과 연관된 로직이기는 하나 화면을 구성하는 코드에 로직이 포함된다는 게 마음에 들지는 않았다.

 

TCA 작동 방식

TCA 구성 요소

  • State
    비즈니스 로직을 수행하거나 UI를 그릴 때 필요한 데이터의 집합. 기존에 @State로 감싸인 데이터 변수라고 생각하면 편하다.
  • Action
    사용자에 의해 뷰에서 발생하는 모든 action과 API호출 결과를 나타내는 타입.
  • Dependency
    API 클라이언트를 비롯한 외부 시스템과 같이 어플리케이션이 필요로 하는 의존성(Dependency)을 가지고 있는 타입. UUID나 Date의 초기화등도 포함.
  • Effect
    네트워크 요청, 디스크에서 저장/로드, 타이머 생성, Dependency와 상호 작용과 같은 작업을 수행하는 Reduce()의 리턴값. 통신의 결과라고 생각하면 편하다.
  • Reduce
    Action을 전달받아 이를 처리한 결과로 State의 상태를 변경해 UI를 업데이트하는 로직. 
    API 요청과 같은 이벤트를 Effect와 Dependency를 이용해 실행하고, 실행한 결과는 Action으로 다시 Reducer에 전달된다.
  • Store
     실제로 기능이 작동하는 공간(공식 문서에는 runtime이라 표현한다). Action을 트리거로 Store는 Reducer와 Effect를 실행할 수 있고, 이로 인해 Store에서 일어나는 State 변화로 UI를 업데이트한다.

구성 요소의 흐름

  1. 사용자는 View를 통해 Action을 생성하고, 생성된 Action은 Reducer로 삽입된다. (앱 내 간단한 로직 처리(통신이 필요없는)가 가능하면 Reducer -> State 도 가능)
  2. Reducer가 Dependency를 실행하고 그 결과를 Effect 타입으로 반환. Effect는 통신의 결과이며, 개발자가 의도하지 않는 Effect는 Side Effect라 칭한다
  3. 모든 Effect 각각을 Action으로 받아, 다시 Reducer에 넘겨 로직을 실행한다.

 

Tutorial

표시된 숫자를 + 버튼 , - 버튼을 눌러 값을 변경해보자

먼저 프로젝트 swift-composable-architecture 패키지를 추가한다.
import ComposableArchitecture 로 사용.

구현 순서는 공식 튜토리얼을 따라감

Reducer 구현

@Reducer 매크로를 사용해 구조체를 선언한다. 해당 Struct는 Reducer 프로토콜을 준수한다.
위 TCA 구성요소에서 살펴봤던 State와 Action을 확인할 수 있다. 이때 State는 반드시 Equatable 프로토콜을 준수해야한다.

body에서 Reducer가 State와 Action을 인자로 받아. 특정 action으로 특정 state를 변경하는 것을 확인할 수 있다.

 

SwiftUI View 구현

SwiftUI를 사용해 뷰 컴포넌트를 구현한다. 이때 store를 let으로 선언하는 부분에서 데이터의 단방향 플로우를 엿볼 수 있다. View에서는 Action만 Reducer에 보낼 뿐 State를 직접 변경할 수 없다.

 

State 값 추적

 Reducer는 ._printChanges() 라는 유용한 디버깅용 메서드를 가지고 있다. 이 메서드는 Reducer가 진행하는 모든 Action과 그에 대한 State 변화를 콘솔에 찍어준다.

 

결과

 

 

 

잘못된 개념이나 오탈자는 댓글로 부탁드립니다.

 

 

참고

https://medium.com/naverfinancial/네이버페이-워치앱-tca-적용기-655f1d1b8c23