TCA, The next iOS Architecture ?

Chetan Kumar
4 min readMar 9, 2023

--

Background

Recently I came across a new architectural pattern called TCA (The Composable Architecture). When I explored more on this. I discovered that it’s not only a design pattern which emphasis much on readability, consistency. It’s actually a package which fits and compliments SwiftUI and Combine hand in hand.

Why TCA ?

Let’s understand the need of TCA. This will definitely make us curious to explore further on TCA and possibly integrating the same in our projects.

  • Side Effects : External world communication’s with our application
  • State Management : How the application behaves for different state values and also pass the states from one screen to another.
  • Composition : In other ways divide and conquer. break the features into smaller, well defined, isolated and individual mini modules
  • Testing : Supports testing of mini modules to integrated features end to end. We can also test how the app behaves for external side effects. This make sure our application is robust.

TCA Intro…

TCA borrows concepts from Redux and ELM architectures. TCA focuses more on composition of individual smaller modules which makes the feature much more simpler to build and manage.

Building blocks of a TCA architecture

  • State: A type that describes the data your feature needs to perform its logic and render its UI.
  • Action: A type that represents all of the actions that can happen in your feature, such as user actions, notifications, event sources and more.
  • Reducer: A function that describes how to evolve the current state of the app to the next state given an action. The reducer is also responsible for returning any effects that should be run, such as API requests, which can be done by returning an Effect value.
  • Store: The runtime that actually drives your feature. You send all user actions to the store so that the store can run the reducer and effects, and you can observe state changes in the store so that you can update UI.

TCA Working…

TCA High Level Design
  • View is the visible to the user and shows the latest state. View listens to user actions and pass the event as an action.
  • These actions are handled by reducer as shown which resides under store
  • Store is a sandbox which contains reducer, state, environment (more about this later).
  • Reducer mutates the state based on action.
  • View gets a publish for state updates and updates the view as required.

Simple example…

Confused ? Let’s write a small example to understand the TCA and how to use the TCA library.

Todays example lets a simple app which gets the current time, current date.

Add dependencies and create a new project

Import ComposableArchitecture and confirm to ReducerProtocol

  • TCA is actually a protocol which mandates the design pattern which can be implemented using below reduce method.
struct DateTimeFeature : ReducerProtocol {
struct State: Equatable {
var title: String
var value: String
var type: DateType
}

enum DateType: Equatable {
case date
case time
case none
}

enum Action: Equatable {
case showCurrentDate
case showCurrentTime
}

func reduce(into state: inout State, action: Action) -> EffectTask<Action> {
switch action {
case .showCurrentTime:
state.title = "Current Time:"
state.value = getTime()
state.type = .time
return .none
case .showCurrentDate:
state.title = "Current Date:"
state.value = getDate()
state.type = .date
return .none
}
}
}
  • struct State is a representation on the view based on the current state at any given time. we have title and value to be shown in view here.
  • enum Action is the possible actions on view where a user can request for Date or Time
  • we also implement the reduce function here which accepts state and action as params. here we need to update the state(which is inout param) based on the action received. we can also return subsequent actions which can be triggered as a result of current action.

Setup SwiftUI View

struct ContentView: View {
let store: StoreOf<DateTimeFeature>

var body: some View {
VStack {
WithViewStore(self.store) { viewStore in
VStack {
HStack {
Text(viewStore.title)
Text(viewStore.value)
}
Spacer(minLength: 60)
switch viewStore.type {
case .date, .none:
Button("Show Time") {
viewStore.send(.showCurrentTime)
}
case .time:
Button("Show Date") {
viewStore.send(.showCurrentDate)
}
}
Spacer()
}
}
}
.padding()
}
}
  • TCA makes it easy to use the DateTimeFeature created above. we simply create a store of type <DateTimeFeature> and implement a view wrapper WithViewStore(self.store) as a parent wrapper for the complete swiftui view.
  • You might be wondering how does the view updates are observed here. WithViewStore(self.store) magically listens and publishes the changes reactively. we simply pass the actions using viewStore.send() and receive the state changes using viewStore.state

This is it…

Where to go from here?

Although this a good demo to start off TCA. TCA makes more sense when we modularise the features to individual reusable standalone components which can put together to form a logical feature. We should also try to explore more on how Effects and Environments are handled to make the most of TCA.

References

--

--