Redux + Swift

Manish Singh
4 min readJul 29, 2022

--

I started working with Redux in 2020 for the first time. When I first started with it in an iOS project, I did not understand the various components of Redux and RxSwift. But over a period of time, I did like this architecture.

Components of the architecture

Store

Reducer

Action

ActionHandler

Middlerware

SideEffects

The main philosophy behind the popularity of REDUX, IMO, is having a single source of truth for state and separation of concern.

Store, ActionHandler, Reducer, Middleware and SideEffects are responsible for different actions.

Store in this architecture is a type that has a reference toActionHandler, Reducer, MiddlerWare, and SideEffects,and Store calls reducer when ActionHandler done making the changes. So, from an app perspective, the app does not need to decide on when to call state mutation logic, its the store which will call reducer to perform that operation.

Types

Action is a type that defines all the events that can happen during the lifetime of an app/view etc.

In a typical use case where there could two events for an app, launchApp, and launchedApp.

enum AppActions: Action {  case launchApp
case launchedApp
}

ActionHandler is a protocol in this design pattern that when implemented can take care of making the async calls for the feature. It's not a networking layer but it's a type that encapsulates all the async operations/core data/user defaults operations etc. ActionHandler notifies Store after the async calls are complete with success or failure and it does it through subscription as done here.

We have an important line here. Let’s see what it's doing, Actions are by nature async but there is a sequence that matters functionality wise such as, in a typical view that appears/updates on the screen after a network call. First, we make a network call -> show a spinner -> then update the UI for success or failure. That's the whole point of this buffer, it stores the next action that should come in the sequence or chain of events.

Now, with that, we have covered two important types one that defines action and the other that implements what to do about those actions.

Let’s take a look at Reducer. The Reducer takes care of actually mutating the state of the app. Now, when a single type takes care of state mutation we don’t need to worry about various floating flags for various purposes, and view/logic can react to the changes in the state easily.

That was Reducer which has an important place in this architecture since its responsible for state mutation and SideEffects. We talked about state mutation, let’s look quickly on SideEffects. It’s a type that is the outcome of the state mutation. SideEffects is an enum in this implementation since there can be many events for different state changes.

Lastly, we have Middleware , It’s a type that’s typically used to perform any action that is needed after actions are handled and state mutation is complete.

Implementation Details

A typical store implementation (based on RxSwift)

Store Implementation

Let's talk about what's happening in this type

It contains references to the type we talked about before and an init block to initialize and then an important function called dispatchActions, dispatchAction and onComplete. Everything else here is pretty typical, so, let's focus on these 3 as these drives the changes in the state which drive changes in the view.

When a typical view gets an event it will call the store dispatchActions and then the store will internally take care of state mutation, if any, by callingreducer-> middleware -> sideeffects and subsequent actions. Take a look at the flowchart, in which, view (Action origination point) -> store which contains all these components.

Since a single source of action, which typically is your view (for example), can generate many actions like a button tap, view update an API call, etc so adding s at the end of action makes sense.

Next, we have dispatchAction that gets called for individual action. This function calls ActionHandler which is a type that takes care of calling any async calls. Typically, your API calls would go here. Once the response comes back your store will be notified since it has attached a subscription to the changes as shown here https://gist.github.com/singh88/0817fd750d2440257a69283e1fd6d99c#file-defaultrxstore-swift-L56.

Next and the last topic in this discussion here is onComplete. This function is important in subscription both error and successful cases.

I think this could be a good stopping point for this part. In this part, we discussed a bit of Redux, talked about its high-level components of it, and got a little bit into the implementation details. You can look into the full implementation here.

--

--

No responses yet