Technology

Exploring the Composable Architecture Framework

Ade Adegoke

April 5, 2023

At Conjure, our iOS team make a real effort to keep up with the latest trends and technologies when it comes to Swift. With using SwiftUI and Combine, there comes the challenge of efficiently managing state.

Last year I attended a talk by Nikita Mounier, where he shared his experiences using the Composable Architecture. In this article, I will give an introduction to this framework.

NSLondon meet-up at Bumble

General Overview

The Composable-Architecture, also known as TCA, which is heavily influenced by Redux was developed by Brandon Williams and Stephen Celis from Point-Free. They believe that this framework offers:

• An opinionated library for building an application in a consistent and understandable way

• Focuses on composition, testing and ergonomics

• Unilateral state management

• Ability to handle side effects

Data flow diagram of how TCA operates

Components:

State — This is an object that defines the data needed for the logic and UI.

Action — an enum to represent all possible modifications of state.

Reducer — A function that manipulates the properties of the state based on an action.

Environment (Optional) — This is for any dependencies used, for example, a networking module.

Store — The store manages all of the above. It receives an action and runs the reducer to modify the state.

Effect — An event that modifies the state outside of its local context.

Demo project

I have created a project using the Composable-Architecture framework that shows nearby bus stops in London. This data come from the public TfL API based on the user’s current location.

Project Setup

To use the Composable Architecture framework, you need to install it into your project. To install the SDK through Swift Package Manager:

• In Xcode, select File > Add Package and enter https://github.com/pointfreeco/swift-composable-architecture as the repository URL

Implementation

As part of using the framework, I needed to create an object called BusStopFeature that conforms to ReducerProtocol. This object houses the State, Action and reducer method.

I really appreciate the way in which it encapsulates these components, as it provides a clear understanding of how the state is modified within this particular module. I also believe that it focuses on the separation of concerns, in terms of individual components such as the state and action. Moreover, using this framework ensures that any modification to the state can only occur within a specific section of the project. I feel this could be vital when it comes down to debugging as everything is centralised.

The BusStopFeature contains two dependencies that are injected using the @Dependencyproperty wrapper. It needs some initial setup to register your dependencies which you can see in TCA+Dependencies.swift in our project.

Walkthrough

To illustrate, let's look at a small example of the overall flow of the architecture. We start when the user interacts with the view, sending an action to the store. A concrete example of this process can be observed in the BusStopView screen when the user taps on a stop. The button triggers the selectStop action passing the selected stop.

The framework provides a method called WithViewStore that enables the view to interact with the store without needing to wrap the store up in an ObservedObject class. Given we are using SwiftUI this helps simplify the code in the view and make it more readable.

After the view sends the selectStop action to the store, this is then passed to the reducer to set the selectedStop property, after which an effect is returned to trigger the setSheet action.

The reducer will then receive the setSheet action and mutate the state again by setting the isSheetPresented. We don’t want to trigger any side effects so we return .none

Once the state has been mutated, the view can listen to the change through WithViewStore and present the sheet. The TCA library allows us to create a binding from the store based on the isSheetPresented property. We can then trigger another action to close the sheet once the user chooses to.

Summary

During the development of this demo project, I found that the flow of TCA provided a clear and intuitive way to understand how the state of the application was being updated. By following the sequence of events, it was easy to trace how the state was being mutated and identify any potential issues.

We have only discussed a small example of using the Composable Architecture in this article, and there are so many more features that the framework allows.

Overall, I found TCA to be a powerful and effective framework for managing the state in an iOS application. There is obviously a learning process when it comes to using the framework, but I would definitely recommend it to any developer looking to streamline their state management process.