Exploring the Composable Architecture Framework
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 @Dependency
property 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.
Source code
If you would like to view the source code you can here https://github.com/conjure/demo-ios-tca
Useful links
Point-Free Composable Architecture — https://www.pointfree.co/collections/composable-architecture
Video by Swift & Tips — https://youtu.be/SfFDj6qT-xg
Video by Zach Eriksen — https://youtu.be/MmzMHNO9cno