Using Redux and Swift

Reeeewind

Image for post
Image for post
Photo by Daniel Schludi on Unsplash

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

Prerequisites:

  • Coding in Swift Playgrounds (guide HERE)

Terminology:

Redux: an open-source JavaScript library for managing application state

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).

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

Updating a UI component can either be done with the Redux store, perhaps storing text within a label.

Redux:

  • Call an action
  • Pass data to a reducer
  • Update the store

Imperative:

  • 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

We create a Single View Project, and then we use Swift Package Manager to include the dependency from https://github.com/ReSwift/ReSwift (up to next major).

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.

Image for post
Image for post

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.

The code

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.

Image for post
Image for post
Click for Gist

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.

Image for post
Image for post
Click for Gist

This connects to a Person struct simply contains the name of each Person

Image for post
Image for post
Click for Gist

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.

Image for post
Image for post
Click for Gist

The action is a rather trivial struct, as shown in the following code snippet.

Image for post
Image for post
Click for Gist

this is tied together through the following ViewController. Note how it conforms to the StoreSubscriber 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 mainStore within viewDidLoad() here through the mainStore call mainStore.subscribe(self) that binds the view controller to the mainStore.

Image for post
Image for post
Click for Gist

Conclusion

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

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store