An OOP Flux implementation in Swift

Hi, my name is Hung Dinh. I’m a senior iOS developer at HRCloud Inc. Today, I'm going to talk about the problems we face when applying Flux Architecture to our products and how we customize Flux to fit this architecture with our projects (you don't need to customize the original Flux if you are not having the same problems).

This article assumes that you are already familiar with Flux but if not, here is a resource to get started:

One and a half year ago, I started studying Flux Architecture. After built few examples in Swift, I introduced my manager and coworkers to these examples along with Flux Architecture. Most of them were very interested in this new idea and we decided to apply this idea to our products on both iOS and Android platforms. However, there were a few questions that need us to clarify:

  1. Can we release the stores if they are not being used anymore?

a. Problem

In Flux, the dispatcher is supposed to dispatch each action to all of the stores.

Each store registers itself and provides a callback. When an action creator provides the dispatcher with a new action, all stores in the application receive the action via the callbacks in the registry” — Flux in depth overview

This means that all of them need to be keep alive along with the application, even they are not being used in any views. We should find out an approach to release unused stores to reduce memory usage.

b. Approach

After investigating, we all agreed that an action should do a single job (Single Responsibility) and it mostly affects to only one store. If other stores need to be updated when executing that action, another action should be dispatched inside that one. Finally, we decided that an action won't be dispatched to every stores any more. Instead, each action should be dispatched to a specific store so that other stores can be gone away if it is not being used in any views.

2. Can we avoid violating Open Close Principle in SOLID?

a. Problem

In the original Flux implementation, when we add a new action, we also have to add a new ‘case’ statement into ‘reduce’ function in the store. The same problem when removing an action. That makes OOP folks like me confused if we are violating the Open Close principle in SOLID or not.

Here is an example for Todo application that Facebook provides in GitHub.

b. Approach

An action should know what side-effect should be executed and how to transform the state by itself. So we add a new base Action class

public class Action {
// This pure function describes how to transform the state
func reduce(state: State, sideEffectResult: Result) -> State?
    // This is for executing side-effects like requesting API, ...
func execute(state: State) -> Result
    // This is to identify what store this action belongs to
var store: Store<State> { get }

With this approach, we don't have to modify the stores, what we should do is to create a new action inheriting from the base action above, then override the functions and property above. In addition, we can easily writing unit-test for that standalone action without having to writing unit-test for any store.

2. Is there any flexible way to manage dependencies between actions.

a. Problem

In the real world, we need to manage the dependencies between actions, but it seems that the waitFor method that original Flux implementation provides can not cover some cases that we face. Let me give you some examples:

  • Example #1: User pulls to refresh, PullToRefreshAction will be fired. While this action is executing, user pulls to refresh again. How we cancel one of them?
  • Example #2: We have these two actions A1, A2, both of them request to API asynchronously. A2 have to wait for A1 requests to API completely in order to be executed. How we control this flow?

b. Approach

  • Example #1: Define a Rule as below, then attach to the store.
UniqueRule(PullToRefreshAction.self, cancelBehavior: .first, condition: Your-Closure)

‘condition’ is an optional closure parameter that allows us to have more control about when should cancel the action.

‘cancelBehavior: .first’ means that the first action will be canceled. Otherwise, the latest action will be ignored.

  • Example #2:
SequenceRule(A1.self, A2.self, condition: your-closure)

Or we can define new rules by inheriting protocol Rule.

protocol Rule {
func execute(a: ExecutingAction, actions: [ExecutingAction])

3. Can we execute actions in a background thread?

a. Problem

Since we have actions executing in sequence that i have said in the above question. The Dispatcher will need more time to execute queued actions. That might causes the UI not responsive if we dispatch and execute actions in the UI thread like original Flux does.

b. Approach:

Our dispatcher will dispatch and execute actions in the background thread. After completed any action, state changes will be propagated to UI in the UI thread.


To demonstrate how the customizations work, lets implement a simple demo application: CounterExample

Firstly, create a new store named CounterStore

Secondly, add a new action named IncreaseAction

Finally, dispatch this action from ViewController

IncreaseAction(additionValue: 1).dispatch()

That’s all for a simple counter application.

In the next example, I’m going to introduce you how to do some side-effects like calling API, reading database or doing intensive calculation.

Create a new action ComplexAction, override ‘execute’ method and implement side-effects logic inside this method. In this example, we suppose that the ‘execute’ method returns an integer value after doing a long task that takes 5 seconds to complete.

Everything is ready. From the ViewController, dispatch the action:


The source code for these example is available on GitHub at

If you are interested in this approach, please visit

If you have any concerns, please leave a comment.

Thank you!

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.