Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/inamiy/reactiveautomaton
đ€ ReactiveCocoa + State Machine, inspired by Redux and Elm.
https://github.com/inamiy/reactiveautomaton
automaton elm reactivecocoa redux state-machine swift
Last synced: 4 months ago
JSON representation
đ€ ReactiveCocoa + State Machine, inspired by Redux and Elm.
- Host: GitHub
- URL: https://github.com/inamiy/reactiveautomaton
- Owner: inamiy
- License: mit
- Archived: true
- Created: 2016-05-06T19:39:20.000Z (over 8 years ago)
- Default Branch: swift/5.0
- Last Pushed: 2021-12-12T05:05:45.000Z (about 3 years ago)
- Last Synced: 2024-09-25T22:43:37.212Z (4 months ago)
- Topics: automaton, elm, reactivecocoa, redux, state-machine, swift
- Language: Swift
- Homepage:
- Size: 293 KB
- Stars: 207
- Watchers: 7
- Forks: 6
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
## NOTE: This repository has been discontinued in favor of [Actomaton](https://github.com/inamiy/Actomaton).
# ReactiveAutomaton
[ReactiveCocoa](https://github.com/ReactiveCocoa/ReactiveCocoa) + State Machine, inspired by [Redux](https://github.com/reactjs/redux) and [Elm](http://elm-lang.org/). A successor of [SwiftState](https://github.com/ReactKit/SwiftState).
## Example
(Demo app is available at [ReactiveCocoaCatalog](https://github.com/inamiy/ReactiveCocoaCatalog))
![](Assets/login-diagram.png)
To make a state transition diagram like above _with additional effects_, follow these steps:
```swift
// 1. Define `State`s and `Input`s.
enum State {
case loggedOut, loggingIn, loggedIn, loggingOut
}enum Input {
case login, loginOK, logout, logoutOK
case forceLogout
}// Additional effects (`SignalProducer`s) while state-transitioning.
// (NOTE: Use `SignalProducer.empty` for no effect)
let loginOKProducer = /* show UI, setup DB, request APIs, ..., and send `Input.loginOK` */
let logoutOKProducer = /* show UI, clear cache, cancel APIs, ..., and send `Input.logoutOK` */
let forceLogoutOKProducer = /* do something more special, ..., and send `Input.logoutOK` */let canForceLogout: (State) -> Bool = [.loggingIn, .loggedIn].contains
// 2. Setup state-transition mappings.
let mappings: [Automaton.EffectMapping] = [/* Input | fromState => toState | Effect */
/* ----------------------------------------------------------*/
.login | .loggedOut => .loggingIn | loginOKProducer,
.loginOK | .loggingIn => .loggedIn | .empty,
.logout | .loggedIn => .loggingOut | logoutOKProducer,
.logoutOK | .loggingOut => .loggedOut | .empty,.forceLogout | canForceLogout => .loggingOut | forceLogoutOKProducer
]// 3. Prepare input pipe for sending `Input` to `Automaton`.
let (inputSignal, inputObserver) = Signal.pipe()// 4. Setup `Automaton`.
let automaton = Automaton(
state: .loggedOut,
input: inputSignal,
mapping: reduce(mappings), // combine mappings using `reduce` helper
strategy: .latest // NOTE: `.latest` cancels previous running effect
)// Observe state-transition replies (`.success` or `.failure`).
automaton.replies.observeNext { reply in
print("received reply = \(reply)")
}// Observe current state changes.
automaton.state.producer.startWithValues { state in
print("current state = \(state)")
}
```And let's test!
```swift
let send = inputObserver.send(value:)expect(automaton.state.value) == .loggedIn // already logged in
send(Input.logout)
expect(automaton.state.value) == .loggingOut // logging out...
// `logoutOKProducer` will automatically send `Input.logoutOK` later
// and transit to `State.loggedOut`.expect(automaton.state.value) == .loggedOut // already logged out
send(Input.login)
expect(automaton.state.value) == .loggingIn // logging in...
// `loginOKProducer` will automatically send `Input.loginOK` later
// and transit to `State.loggedIn`.// đšđœ < But wait, there's more!
// Let's send `Input.forceLogout` immediately after `State.loggingIn`.send(Input.forceLogout) // đ„đŁđ„
expect(automaton.state.value) == .loggingOut // logging out...
// `forceLogoutOKProducer` will automatically send `Input.logoutOK` later
// and transit to `State.loggedOut`.
```Note that **any sizes of `State` and `Input` will work using `ReactiveAutomaton`**, from single state (like above example) to covering whole app's states (like React.js + Redux architecture).
## References
1. [iOSDC 2016 (Tokyo, in Japanese)](https://iosdc.jp/2016/) (2016/08/20)
- [iOSDC Japan 2016 08/20 Track A / Reactive State Machine / çšČèŠ æł°ćź - YouTube](https://www.youtube.com/watch?v=Yvz9H9AWGFM) (video)
- [Reactive State Machine (Japanese) // Speaker Deck](https://speakerdeck.com/inamiy/reactive-state-machine-japanese) (slide)
2. [iOSConf SG (Singapore, in English)](http://iosconf.sg/) (2016/10/20-21)
- [Reactive State Machine - iOS Conf SG 2016 - YouTube](https://www.youtube.com/watch?v=Oau4JjJP3nA) (video)
- [Reactive State Machine // Speaker Deck](https://speakerdeck.com/inamiy/reactive-state-machine-1) (slide)## License
[MIT](LICENSE)