The Swift Composable Architecture: A Software Engineer's Guide


The Swift Composable Architecture: A Software Engineer's Guide

pointfreeco/swift-composable-architecture

2025-08-10

At its core, TCA is a library for building applications in a consistent and understandable way, with a strong focus on composition, testing, and ergonomics. It provides a clear and predictable way to manage your application's state, actions, and side effects.

Think of it this way
a traditional UIKit app can sometimes feel like a jumbled mess of view controllers, delegates, and callbacks. It's easy for the flow of data to become unclear and for bugs to hide in the corners. TCA brings a predictable, one-way data flow to your app.

Here's the key vocabulary

State
A simple struct that holds the data for a particular feature. This is a single source of truth.

Action
An enum that represents every possible thing that can happen in your feature, from user taps to data loading responses.

Reducer
A function that takes the current State and an Action, and returns a new State. This is where all your business logic lives.

Store
The object that holds the state and runs the reducer. It's the central hub for your feature.

With TCA, all of your application logic is contained within the Reducer function. This makes it incredibly easy to unit test. You don't need to mock a view controller or a network layer; you can just pass a State and an Action to your reducer and assert that the new State is what you expect. This is a huge win for reliability and confidence in your codebase.

TCA is designed for composition. You can build small, self-contained features and then combine them to create larger, more complex features. For example, you can have a "login" feature and a "user profile" feature, and then compose them together into a "main app" feature. This makes your code more modular and easier to manage as your app grows.

The architecture forces a clear separation between your UI (UIView or UIViewController), your business logic (Reducer), and your state (State). This makes your codebase easier to read, understand, and maintain, especially for new team members.

You can add the library to your Xcode project using the Swift Package Manager.

In Xcode, go to File > Add Packages...

Paste the repository URL
https://github.com/pointfreeco/swift-composable-architecture

Let's build a classic counter feature. It will have a state, actions, and a reducer.

import ComposableArchitecture

// MARK: - State
// The data for our feature.
struct CounterState: Equatable {
    var count = 0
}

// MARK: - Action
// Every possible thing that can happen in our feature.
enum CounterAction: Equatable {
    case decrementButtonTapped
    case incrementButtonTapped
}

// MARK: - Reducer
// The business logic that changes our state.
let counterReducer = Reducer<CounterState, CounterAction, Void> {
    state, action, _ in
    switch action {
    case .decrementButtonTapped:
        state.count -= 1
        return .none
    case .incrementButtonTapped:
        state.count += 1
        return .none
    }
}

Now you can create a Store in your UIViewController and use it to drive your UI.

import UIKit
import ComposableArchitecture

class CounterViewController: UIViewController {

    let store: Store<CounterState, CounterAction>

    private lazy var viewStore = ViewStore(store)

    init(store: Store<CounterState, CounterAction>) {
        self.store = store
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
        
        // This is how you observe state changes and update the UI.
        self.viewStore.publisher.count
            .removeDuplicates()
            .sink { [weak self] count in
                self?.countLabel.text = "\(count)"
            }
            .store(in: &cancellables)
    }

    // You send actions to the store when a button is tapped.
    @objc private func incrementTapped() {
        self.viewStore.send(.incrementButtonTapped)
    }

    @objc private func decrementTapped() {
        self.viewStore.send(.decrementButtonTapped)
    }
    
    // ... UI setup for buttons and label ...
}

This simple example shows the core concepts
your UI sends Actions to the Store, the Reducer updates the State, and the UI then reacts to the State changes. It creates a predictable loop that makes your application logic much more manageable.


pointfreeco/swift-composable-architecture




High-Performance Desktop Development: An Engineer's Guide to gpui-component in Rust

This project provides a set of reusable GUI components built on top of the GPUI (GPU User Interface) framework, all written in Rust


Moving Beyond Static Diagrams: A Deep Dive into LikeC4 and the C4 Model

If you’ve ever spent hours in a whiteboard tool only for the diagram to be outdated the moment someone merges a PR, you’re going to love LikeC4