티스토리 뷰

iOS 개발에서 상태 관리(state management) 는 언제나 고민해야 할 중요한 부분이다.
특히, SwiftUI와 함께 사용될 때 상태(State)와 데이터 흐름을 어떻게 관리할 것인가? 는 더욱 중요해진다.

이 문제를 해결하는 강력한 아키텍처 패턴 중 하나가 바로 TCA(The Composable Architecture) 이다.
TCA는 Redux 스타일의 단방향 데이터 흐름을 기반으로, 앱의 상태와 로직을 예측 가능하게 관리할 수 있도록 해준다.

이번 포스팅에서는 TCA의 개념, 핵심 구조, 그리고 실무에서의 활용법까지 살펴보자!


1️⃣ TCA란?

TCA(The Composable Architecture)iOS 및 SwiftUI 앱을 위한 아키텍처 패턴으로,
Point-Free 팀이 개발한 오픈소스 프레임워크다.

 

📌 TCA의 주요 특징
Redux 스타일의 단방향 데이터 흐름을 사용
애플리케이션 상태(State)를 중앙에서 관리
Side Effect(비동기 작업) 처리가 명확함
Composable(조합 가능한) 구조로, 모듈화가 용이
SwiftUI와 궁합이 좋음

즉, TCA는 앱의 상태와 동작을 예측 가능하게 만들고, 테스트하기 쉬운 환경을 제공하는 아키텍처 패턴이다.


2️⃣ TCA의 핵심 개념

TCA의 구조는 크게 State(상태), Reducer(비즈니스 로직), Action(사용자 입력), Environment(외부 의존성) 로 구성된다.

[ State ]        → 앱의 상태를 저장
[ Action ]       → 사용자 입력 및 이벤트 처리
[ Reducer ]      → 액션을 받아 상태를 변경하는 로직
[ Environment ]  → 외부 서비스(API, Database 등)와의 상호작용
[ Store ]        → 전체적인 데이터 흐름을 관리하는 컨테이너

각 컴포넌트를 자세히 살펴보자.

✅ 1. State (상태)

앱의 상태를 나타내는 구조체이다.

struct CounterState: Equatable {
    var count: Int = 0
}

✅ 2. Action (사용자 입력 및 이벤트)

사용자가 버튼을 누르거나, 네트워크 요청이 완료되었을 때 발생하는 액션을 정의한다.

enum CounterAction {
    case increment
    case decrement
}

✅ 3. Reducer (비즈니스 로직)

Reducer는 Action을 받아서 State를 변경하는 로직을 담당한다.

import ComposableArchitecture

let counterReducer = Reducer<CounterState, CounterAction, Void> { state, action, _ in
    switch action {
    case .increment:
        state.count += 1
        return .none
    case .decrement:
        state.count -= 1
        return .none
    }
}

✅ 4. Store (전체 데이터 흐름 관리)

Store는 앱의 상태와 액션을 관리하는 중앙 컨테이너 역할을 한다.

let store = Store(
    initialState: CounterState(),
    reducer: counterReducer,
    environment: ()
)

✅ 5. View (UI)

SwiftUI와 함께 사용되며, Store에서 상태를 구독하고 액션을 보낸다.

import SwiftUI
import ComposableArchitecture

struct CounterView: View {
    let store: Store<CounterState, CounterAction>

    var body: some View {
        WithViewStore(self.store) { viewStore in
            VStack {
                Text("Count: \(viewStore.count)")
                    .font(.largeTitle)
                HStack {
                    Button("-") { viewStore.send(.decrement) }
                    Button("+") { viewStore.send(.increment) }
                }
            }
        }
    }
}

 

📌 핵심 정리

  • Store는 상태를 관리하고, View는 Store의 상태를 구독하며, Reducer는 액션을 받아 상태를 변경한다.
  • SwiftUI의 WithViewStore 를 사용하면 Store에서 상태를 구독하고 UI를 업데이트할 수 있다.

3️⃣ TCA를  활용하는 방법

TCA를 실제 프로젝트에서 어떻게 활용할 수 있을까?
기본적인 Counter 예제에서 확장하여, 네트워크 요청을 포함한 예제를 만들어보자.

📌 API 호출이 필요한 경우

TCA에서는 비동기 API 호출을 Effect(효과) 를 통해 처리한다.

✅ 1. State 정의

struct UserState: Equatable {
    var user: User?
    var isLoading: Bool = false
}

✅ 2. Action 정의

enum UserAction {
    case fetchUser
    case userResponse(Result<User, APIError>)
}

✅ 3. Reducer에서 API 호출 처리

let userReducer = Reducer<UserState, UserAction, APIClient> { state, action, apiClient in
    switch action {
    case .fetchUser:
        state.isLoading = true
        return apiClient.fetchUser()
            .catchToEffect()
            .map(UserAction.userResponse)

    case .userResponse(.success(let user)):
        state.isLoading = false
        state.user = user
        return .none

    case .userResponse(.failure):
        state.isLoading = false
        return .none
    }
}

✅ 4. View에서 액션 전송

struct UserView: View {
    let store: Store<UserState, UserAction>

    var body: some View {
        WithViewStore(self.store) { viewStore in
            VStack {
                if viewStore.isLoading {
                    ProgressView()
                } else if let user = viewStore.user {
                    Text("User: \(user.name)")
                } else {
                    Button("Load User") {
                        viewStore.send(.fetchUser)
                    }
                }
            }
        }
    }
}

📌 이렇게 하면?

  • API 요청이 필요할 때 Effect를 사용하여 비동기 작업을 실행할 수 있다.
  • UI는 상태를 구독하고 자동으로 업데이트된다.

4️⃣ TCA의 장점과 단점

✅ TCA의 장점

단방향 데이터 흐름으로 인해 예측 가능성이 높다.
상태와 로직을 중앙에서 관리하여 코드의 일관성을 유지할 수 있다.
SwiftUI와 완벽하게 통합되며, Combine을 활용한 비동기 처리가 용이하다.
테스트가 쉬운 구조를 제공하여 TDD(Test-Driven Development)에 적합하다.
Composable(조합 가능한) 아키텍처로, 기능을 모듈화하여 재사용성이 높다.

❌ TCA의 단점

🚧 초기 학습 비용이 높다 (Redux 스타일의 개념을 이해해야 함).
🚧 소규모 프로젝트에는 다소 과할 수 있음 (단순한 앱에서는 불필요하게 복잡해질 가능성).
🚧 성능 이슈 (State가 클 경우 업데이트가 많아질 수 있음).


정리

TCA(The Composable Architecture)는 단방향 데이터 흐름을 기반으로 한 강력한 상태 관리 아키텍처
State, Action, Reducer, Store, Environment의 개념을 통해 명확한 구조를 제공
Effect를 사용하여 비동기 API 호출과 같은 Side Effect를 처리할 수 있음
SwiftUI와 함께 사용하면 강력한 조합을 이루며, 테스트가 쉬운 구조를 만들 수 있음

 

TCA는 처음에는 다소 복잡해 보일 수 있지만, 한 번 익숙해지면 확장성과 유지보수성이 뛰어난 코드를 작성할 수 있다.
지금 진행 중인 프로젝트에서 작은 기능부터 TCA를 도입해보면서, 어떤 이점이 있는지 직접 경험해보자

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/04   »
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
글 보관함