Swiftpack.co - Package - clmntcrl/swidux


Swift unidirectional data flow inspired by redux.


This library should be considered alpha, and not stable. Breaking changes will happen often.


Define your application state,

struct AppState {
    var count = 0

the list of actions that could be done,

enum CounterAction: Action {
    case increment
    case decrement

and how they impact the application state.

let counterReducer = Reducer<Int> { state, action in
    switch action {
    case CounterAction.increment: state += 1
    case CounterAction.decrement: state -= 1
    default: break

Then initialize the application store,

let store = Store<AppState>(
    initialState: AppState(),
    reducer: counterReducer.lift(\.count)

subscribe any application state key path to be notified of state changes (make sure to keep reference to the token because its deallocation stop subscription).

let token = store.subscribe(\.count) { print($0) }

Now dispatch actions to mutate application state and use your subscription to state changes to update your UI, ...




Application state must be a value type because Swidux store rely on didSet observer to notify subscribers of state changes.


Reducers use inout State to improve performances. This has a major drawback, the consistency of the state is no longer guaranteed by the reducer but is the responsibility of the developer. It would be if reduce type was (State, Action) -> State but at the cost of State copies.

Let's take the following example:

struct AppState {
    var tasks: [Id<Task>: Task] = [:]
    var todaysTasksIds: [Id<Task>] = []

let reducer = Reducer<AppState> { state, action in
    switch action {
    case TaskAction.create(let title):
        let task = Task(title: title)
        state.todaysTasksIds += [task.id] // ← ‼️ Inconsistent state
        state.tasks[task.id] = task
    default: break

Each mutation of the application state trigger the notification of susbscribers (if the value they have subscribed change). So if someone subscribe to \.todaysTasksIds changes to generate a list of a today's task list like bellow:

let token = store.subscribe(\.todaysTasksIds) { todaysTasksIds in 
    let todaysTasks = todaysTasksIds.map { store.state.tasks[$0] }
    // ...

The inconsistency of the state could crash the application because state.tasks has not yet been updated (this is not certain because subscribers notifications rely on an async dispatch that makes code execution order unpredictable).

In the above example, inverting state.todaysTasksIds += [task.id] and state.tasks[task.id] = task lines fix state inconsistency. Sometimes it could be harder to keep things consitent if reducing action mutates lot of state properties. For those cases the use of mutating func is helpful because didSet observer will only be call after the execution this function.



Add the following dependency to your Cartfile:

github "clmntcrl/swidux" ~> 0.1.1
$ carthage update


Add package as dependency:

import PackageDescription

let package = Package(
    name: "AwesomeProjectName",
    dependencies: [
        .package(url: "https://github.com/clmntcrl/swidux.git", from: "0.1.1"),
    targets: [
        .target(name: "AwesomeProjectName", dependencies: ["Swidux"])
$ swift build


Swidux is released under the MIT license. See LICENSE for details.


Stars: 0
Help us keep the lights on



0.1.1 - Oct 31, 2018

0.1.0 - Oct 18, 2018