Skip to content

ShapovalovIlya/ReduxCore

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

138 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ReduxCore Swift: Unidirectional State Management

Store

A thread-safe, observable state container for Swift applications.
Store provides a robust, scalable foundation for managing application state and dispatching actions in a predictable, unidirectional data flow. Inspired by Redux and The Composable Architecture, it is designed to be the central point of state management in your app.

Why Store?

  • Predictable State Management: All state changes are driven by actions and a pure reducer function, making your app’s behavior easy to reason about and debug.
  • Thread Safety: State mutations and action dispatches are performed synchronously on a dedicated dispatch queue, ensuring safety across threads.
  • Observability: State changes are published using @Published, enabling seamless integration with SwiftUI and Combine.
  • Flexible Subscriptions: Support for both strong (drivers) and weak (streamers) subscription models lets you tailor state observation to your use case.
  • Encapsulation: The StoreGraph abstraction allows you to expose only the current state and dispatch capability to child components, preserving encapsulation and reducing coupling.

Key Features

  • Generic over State and Action types
  • Strong and weak subscription models
  • Synchronous and asynchronous state streaming
  • Type-safe reducer mechanism
  • Published state for Combine and SwiftUI integration
  • Designed for scalable, modular applications

Example

enum CounterAction { case increment, decrement }

struct CounterState {
    var count: Int = 0
}

let reducer: Store<CounterState, CounterAction>.Reducer = { state, action in
    switch action {
    case .increment: state.count += 1
    case .decrement: state.count -= 1
    }
}

let store = Store<CounterState, CounterAction>(initial: CounterState(), reducer: reducer)
store.dispatch(.increment)

See the documentation for more usage patterns, subscription models, and advanced scenarios.

Graph

The ‎Graph object is a lightweight, value-type abstraction that encapsulates a snapshot of the store’s state along with a type-safe action dispatcher. Designed for simplicity and modularity, ‎Graph enables child components and views to read state and dispatch actions without exposing the full store or its internals. Instances are cheap to copy and pass around, making them ideal for performance-sensitive and highly composable architectures.

Key Features

  • State Snapshot: Holds an immutable snapshot of the application state at the time it is created.
  • Type-Safe Dispatch: Provides a dispatcher function for sending single or multiple actions to the store.
  • Sendable: Can be safely passed between threads or used in concurrent contexts.
  • Encapsulation: Enables unidirectional data flow and modular architecture by exposing only what’s needed for state reading and action dispatching.

Usage Example

let graph = store.graph
print(graph.state)           // Access the current state snapshot
graph.dispatch(.increment)   // Dispatch a single action
graph.dispatch(.reset, .increment) // Dispatch multiple actions
graph.dispatch(contentsOf: [.decrement, .increment])

Note:

  • The Graph instance itself does not subscribe to store updates.
  • To observe changes over time, access the latest graph from the store or subscribe using a streamer or driver.

StateStreamer

StateStreamer is a generic, asynchronous, thread-safe utility for broadcasting state updates to multiple consumers using Swift Concurrency. It provides an AsyncStream-based interface for emitting values over time, making it ideal for scenarios where you want to observe and react to state changes as they happen—such as in Redux-like or unidirectional data flow architectures.

Key Features

  • Asynchronous State Streaming: Consumers can observe state updates using for await loops or by iterating over the provided AsyncStream.
  • Configurable Buffering: Control how many state values are buffered if there are no active consumers, helping to manage memory and backpressure.
  • Automatic Stream Completion: The stream completes automatically when the StateStreamer is deinitialized or when finish() is called, notifying all consumers.
  • Thread Safety: All operations are safe to call from any thread.

Usage Example

let streamer = StateStreamer<MyState>()

// Consuming state updates asynchronously
Task {
    for await state in streamer {
        print("Received state update: \(state)")
    }
}

// Emitting a new state update
streamer.yield(newState)

// Finishing the stream (notifying all consumers)
streamer.finish()

Note:

  • After the stream is finished or the streamer is deinitialized, no further values can be yielded.
  • StateStreamer is especially useful for integrating with async/await workflows, Combine pipelines, or custom state management solutions.

About

Core instruments for developing App with Redux architecture.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages