As everyone knows this year the Apple WWDC 2020 won't take place in San José due to the Covid-19 pandemic. Instead Apple...
Flux pattern in Swift
An easy approach to a unidirectional data flow.
In the bucket of architectural patterns we see and often use, there’s one in particular I want to write about since I joined Automattic . Its name is Flux.
But what is Flux?
It’s a unidirectional data flow application architecture used by Facebook for building client-side web applications. It complements React’s composable view components.
You can find more in depth information about it here.
Structure and unidirectional flow
As mentioned before Flux has a unidirectional data flow. But what does it mean?

As you can see in the diagram above the pattern is mainly structured in 4 components:
- Action
- Dispatcher
- Store
- View
An Action, originated from a user interactions with the view, is sent to the Dispatcher, central hub observed by the Store. After the action is dispatched and executed, the Store will emit a change to alert the view the data layer has changed.
The Store is what holds the data and business logic about a specific domain in the application. It’s the only component allowed to modify data in response to a dispatched Action. It always decides when to initiate a network request, either when an Action modifies the data.

How it works in real life?
In Automattic we use this pattern a lot, specially in our WordPress iOS application.
To make our life easy we have built a library called WordPressFlux to help us with the pattern implementation. It also provides two versions of a Store object:
- StatefulStore: a store that holds all of its internal state in a generic State property.
- QueryStore: a mechanism for Stores to keep track of queries by consumers and perform operations depending of those.
That said let’s see how Flux works in an iOS application. The first step is define the Store and its State.
struct InfoStoreState {
var status: FetchingStatus = .idle
var sections: [InfoSection] = []
}
class InfoStore<Service: RemoteService>: StatefulStore<InfoStoreState> {
private weak var service: Service?
init(service: Service) {
self.service = service
super.init(initialState: InfoStoreState())
}
override func onDispatch(_ action: Action) {
guard let action = action as? InfoStoreAction else {
return
}
switch action {
case .fetch:
fetchInfo()
}
}
func getSections() -> [InfoSection] {
return state.sections
}
}
Then we need to define all the actions that can be performed
enum InfoStoreAction: Action {
case fetch
}
InfoStoreState is the entity used to store the data for this specific domain. The InfoStore, initialized with the State, observes the global dispatcher and executes an InfoStoreAction in
override func onDispatch(_ action: Action) {
...
}
Dispatching an Action is very easy
store.onDispatch(InfoStoreAction.fetch)
If a dispatched and executed Action modifies the data layer (State) the Store needs to emit that change to alert the View.
To do that the Store can use the method
emitChange()
or use the helper method provided by the StatefulStore (or QueryStore) to group several state changes into the same change event
transaction { state in
state.sections = result.getSuccess()?.sections ?? []
state.status = .fetchingCompleted(error: result.getError())
}
Bind the View
To bind the view when the Store State changes I can use a view model implementing the Observable protocol the library provides.
The view model will keep a reference to the Store, its Receipt and will observe the Store State changes
init(store: InfoStore<Service>) {
self.store = store
storeReceipt = store.onStateChange { [weak self] (_, state) in
switch state.status {
case .idle:
self?.state = .stationary
case .fetching:
self?.state = .loading
case .fetchingCompleted(let error):
self?.state = .completed(error == nil)
}
}
}
Having the view model compliant to the Observable protocol makes its implementation very easy
receipt = viewModel.onChange { [unowned self] in
self.updateView()
}
I made a small example app you can use to play with Flux
Where to go from here
This pattern can be used with SwiftUI and Combine. I’m working on an example to show you how Flux matches perfectly our expectations.
Stay Tuned!