Swiftpack.co - Package - NoTests/RxFeedback.swift
Swiftpack.co is a collection of thousands of indexed Swift packages. Search packages.


Travis CI platforms pod Carthage compatible Swift Package Manager compatible

The simplest architecture for RxSwift

    typealias Feedback<State, Event> = (Observable<State>) -> Observable<Event>

    public static func system<State, Event>(
        initialState: State,
        reduce: @escaping (State, Event) -> State,
        feedback: Feedback<State, Event>...
    ) -> Observable<State>


  • Straightforward

    • If it did happen -> Event
    • If it should happen -> Request
    • To fulfill Request -> Feedback loop
  • Declarative

    • System behavior is first declaratively specified and effects begin after subscribe is called => Compile time proof there are no "unhandled states"
  • Debugging is easier

    • A lot of logic is just normal pure function that can be debugged using Xcode debugger, or just printing the commands.
  • Can be applied on any level

    • Entire system
    • application (state is stored inside a database, CoreData, Firebase, Realm)
    • view controller (state is stored inside system operator)
    • inside feedback loop (another system operator inside feedback loop)
  • Works awesome with dependency injection

  • Testing

    • Reducer is a pure function, just call it and assert results
    • In case effects are being tested -> TestScheduler
  • Can model circular dependencies

  • Completely separates business logic from effects (Rx).

    • Business logic can be transpiled between platforms (ShiftJS, C++, J2ObjC)


Simple UI Feedback loop

Complete example

    initialState: 0,
    reduce: { (state, event) -> State in
        switch event {
        case .increment:
            return state + 1
        case .decrement:
            return state - 1
    scheduler: MainScheduler.instance,
        // UI is user feedback
        bind(self) { me, state -> Bindings<Event> in
            let subscriptions = [
                state.map(String.init).bind(to: me.label.rx.text)

            let events = [
                me.plus.rx.tap.map { Event.increment },
                me.minus.rx.tap.map { Event.decrement }

            return Bindings(
                subscriptions: subscriptions,
                events: events

Play Catch

Simple automatic feedback loop.

Complete example

    initialState: State.humanHasIt,
    reduce: { (state: State, event: Event) -> State in
        switch event {
        case .throwToMachine:
            return .machineHasIt
        case .throwToHuman:
            return .humanHasIt
    scheduler: MainScheduler.instance,
        // UI is human feedback
        // NoUI, machine feedback
        react(request: { $0.machinePitching }, effects: { (_) -> Observable<Event> in
            return Observable<Int>
                .timer(1.0, scheduler: MainScheduler.instance)
                .map { _ in Event.throwToHuman }


Complete example

    initialState: State.empty,
    reduce: State.reduce,
        // UI, user feedback
        // NoUI, automatic feedback
        react(request: { $0.loadNextPage }, effects: { resource in
            return URLSession.shared.loadRepositories(resource: resource)
                .asSignal(onErrorJustReturn: .failure(.offline))

Run RxFeedback.xcodeproj > Example to find out more.



CocoaPods is a dependency manager for Cocoa projects. You can install it with the following command:

$ gem install cocoapods

To integrate RxFeedback into your Xcode project using CocoaPods, specify it in your Podfile:

pod 'RxFeedback', '~> 3.0'

Then, run the following command:

$ pod install


Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.

You can install Carthage with Homebrew using the following command:

$ brew update
$ brew install carthage

To integrate RxFeedback into your Xcode project using Carthage, specify it in your Cartfile:

github "NoTests/RxFeedback" ~> 3.0

Run carthage update to build the framework and drag the built RxFeedback.framework into your Xcode project. As RxFeedback depends on RxSwift and RxCocoa you need to drag the RxSwift.framework and RxCocoa.framework into your Xcode project as well.

Swift Package Manager

The Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into the swift compiler.

Once you have your Swift package set up, adding RxFeedback as a dependency is as easy as adding it to the dependencies value of your Package.swift.

dependencies: [
    .package(url: "https://github.com/NoTests/RxFeedback.swift.git", majorVersion: 1)

Difference from other architectures

  • Elm - pretty close, feedback loops for effects instead of Cmd, which effects to perform are encoded into state and queried by feedback loops
  • Redux - kind of like this, but feedback loops instead of middleware
  • Redux-Observable - observables observe state vs. being inside middleware between view and state
  • Cycle.js - no simple explanation :), ask @andrestaltz
  • MVVM - separates state from effects and doesn't require a view


Stars: 922



Six - 2021-01-14T05:56:16

Support RxSwift 6

Universal - 2019-02-09T18:28:32

  • Renames Mutation to Event.
  • Removes deprecated APIs.
  • Adds the most general version of feedback loop
public func react<State, Request: Equatable, RequestID, Event>(
    requests: @escaping (State) -> [RequestID: Request],
    effects: @escaping (_ initial: Request, _ state: Observable<Request>) -> Observable<Event>
) -> (ObservableSchedulerContext<State>) -> Observable<Event> {
  • Simpler feedback loops are now just a specialization of the general one.
  • Removes hacky versions of feedback loops that existed because Swift compiler didn't generate automatic Equality conformance.

- 2018-11-13T19:02:50

  • Fixes problem building with Carthage. #41

- 2018-09-21T20:54:17

  • Xcode 10 compatbility
  • Renames Event to Mutation.

- 2018-06-13T21:57:37

  • Fixes problem with feedback loop termination.

- 2017-12-06T12:45:17

  • Fixes duplicated plist inclusion.

- 2017-11-09T08:12:02

  • Fixes leak in Hashable overload of react feedback loop.
  • Shares final guard against reentrancy (if feedback loops have implementation issue and are synchronous) between all feedback loops.

- 2017-10-22T21:57:07

  • Deprecates UI.* in favor of free methods.
  • Deprecates feedback loops of the form Driver<State> -> Driver<Event> in favor of Driver<State> -> Signal<Event>.
  • Adaptations for RxSwift 4.0.0.

- 2017-09-10T22:42:19

  • Adds reentrancy guards to UI.bind feedback loop (Driver version).

- 2017-09-02T10:59:17

  • Includes additional reentrancy checks in DEBUG builds.

- 2017-08-13T22:29:03

  • Adapts UI extensions.

- 2017-08-13T22:01:25

  • Improves reentrancy properties.
  • Adds ObservableSchedulerContext and additional system operator overload that enables passing of scheduler to feedback loops to improve cancellation guarantees.
  • Improves built in feedback loops with additional cancellation guarantees.
    • Receiving stale events by using built-in feedback loops shouldn't be possible anymore.
  • Deprecates feedback loops that don't use scheduler argument.