Using Redux and Swift
Redux is a state management system. Intrigued? Read on
Difficulty: Beginner | Easy | Normal | Challenging
This article has been developed using Xcode 11.4.1, and Swift 5.2.2
- Coding in Swift Playgrounds (guide HERE)
Using Redux in Projects
- Pure reducer functions make business logic easy to test
- Centralising the state makes debugging easy to perform
- Data normalization is encouraged, so that you don’t end up with multiple, independent copies of the same data that are unaware of one another
- State can be persisted to local storage, which can then be used to boot from
- Because redux is strict about code organisation,
- Easy to debug
- People often jump into Redux too early, when it is not really required — you should only implement it if you require a state management tool
- The state itself is immutable, and can only be updated by the reducer. This in itself could put increased memory demands on the system
- Restricted design with boilerplate code
- The rigidness and complexity that make redux suitable for very large projects means it is often not suitable for many small projects
- Actions are disconnected from their effects (which is stored in the Reducer)
State: The state of the application which is considered the source of truth. Although there can only be a single state, it can be divided into sub-states.
Actions: Objects that describe what the system can do. Dispatched by the view as intentions to change the state of the application.
Reducers: The main logic of the application and create a new state for the application given an action and the current state. They must be pure functions with no side effects, and synchronous (this is touched on in the conclusion, but this is why this sample project does not contain any networking features).
The connection with MVI
There is a connection with Android and more specifically MVI here.
So Redux actually is MVI because the reducer is the model, actions are the intent and the state is … redux
UI Component Management
Updating a UI component can either be done with the Redux store, perhaps storing text within a label.
- Call an action
- Pass data to a reducer
- Update the store
- Maintain a local state variable
The decision is what to keep in store, and what to choose to keep in state (and even thinking of this as a battle between declarative and imperative programming). The temptation to keep everything in state is strong — but for (trivial?) UI elements it doesn’t make sense to overload the state with each and every component.
The Example project
Creating the project
The functionality of the App
This particular App will have a an array of people
let people: [Person] = [Person(name: “James”), Person(name: “Ahmed”)]
and will display the Person’s name one at a time starting with the initial person. When the
next button is pressed, the next person in the list is displayed.
Yes it is ugly.
Yes it is just a
UILabel on an view controller with a
UIButton at the bottom. There’s nothing exciting here — this is intended to be an architecture article so please do bear with me.
Note that most (if not all) of these classes will need to
import ReSwift — so with that said let’s get our feet wet!
There is a main store, that I put into a
Constants.swift file. This is where a
middleware could also be declared.
The AppState is where the main meat of this project lies — here we have an
array of person and a
currentIndex that acts as a pointer to the relevant person in the list.
This connects to a
struct simply contains the name of each
The reducer is the business logic of the App, and also initializes the intial state if one is not provided when the
reducer is called.
The action is a rather trivial
struct, as shown in the following code snippet.
this is tied together through the following
ViewController. Note how it conforms to the
protocol that means we are required to add a
typealias as shown in the code snippet. The button action creates a
dispatch action that hits the reducer — fantastic! When the reducer performs it’s work, it hits the
newState function and as the code below shows — but unfortunately this returns the whole state (rather than a slice of the state).
Oh, and we must have made sure that we have subscribed to the
viewDidLoad() here through the
mainStore.subscribe(self) that binds the view controller to the
The next stage to this would be to add middleware, which provides an extension point between dispatching an action and that action reaching the reducer which would then bring us on to thinking about redux-thunk. Put simply, the reducers here should be pure functions (without side-effects) meaning API calls can’t be done within a reducer — this is getting a little complicated and would therefore need an article itself!
Looking back on this article we can see that ReSwift doesn’t (yet) do a diff on the state — so just returns newState when the state changes which means that (in this particular implementation) this would need to be handled in the view, something that clearly wouldn’t be great.
Would I use ReSwift in a production App? Well, SwiftUI might be the most productive way forwards in managing state and making progress in this area, rather than looking to the web or Android for solutions.
Oh. Do you want a Repo with an example project. Consider it done.
If you’ve any questions, comments or suggestions please hit me up on Twitter
Feel free to sign up to my newsletter