
OneWayKit is a reactive unidirectional architecture library built with Combine. It allows you to update the state based on user actions and reflect those changes in the view seamlessly. The library is designed to be simple and easy to integrate into any feature of your application.
ViewFeature defines four key components:
- State: Represents the state of the view.
- Action: Captures user interactions.
- Updater: Updates the state based on actions.
structTimerFeature:ViewFeature{structState:ViewState{varcurrentTime:Float=0varisStarted:Bool=falsevarinterval:TimeInterval=0.1}enumAction:ViewAction{case start
case add
case tapRightButton
case toggleStart
}staticvarupdater:Updater={ state, action invarnewState= state
switch action {case.add:
newState.currentTime +=Float(state.interval)case.toggleStart:
newState.isStarted.toggle()default:break}return newState
}}Middleware plays a key role in handling asynchronous tasks by processing actions from a specific feature and emitting desired actions. Using Combine, it can also emit periodic actions, and subscriptions can be canceled using the cancel(for:) method.
finalclassTimerMiddleware:Middleware{func send(_ action:ViewAction, currentState:anyViewState)->AnyPublisher<ViewAction,Never>{guardlet currentState = currentState as?TimerFeature.Stateelse{returnEmpty().eraseToAnyPublisher()}switch action as?TimerFeature.Action {case.start:returnTimer.publish(every: currentState.interval, on:.main, in:RunLoop.Mode.common).autoconnect().map{ _ inTimerFeature.Action.add
}.eraseToAnyPublisher()case.tapRightButton:if currentState.isStarted {returnPublishers.Merge(Just(TimerFeature.Action.cancel(for:TimerFeature.Action.start)),Just(TimerFeature.Action.toggleStart)).eraseToAnyPublisher()}else{returnPublishers.Merge(Just(TimerFeature.Action.start),Just(TimerFeature.Action.toggleStart)).eraseToAnyPublisher()}default:returnEmpty().eraseToAnyPublisher()}}}2. Now, we use the previously defined ViewFeature to create a OneWay that represents the unidirectional flow of the view, set the initial state, and inject middlewares for side effects.
finalclassTimerViewController:UIViewController{privateletoneway=OneWay<TimerFeature>(initialState:.init(), middlewares:[TimerMiddleWare()])...privatefunc setupOneWay(){
oneway.statePublisher
.map{String(format:"%.1f", $0.currentTime)}.assign(to: \.text, on: timeLabel).store(in:&cancellables)
oneway.statePublisher
.map{ $0.isStarted }.removeDuplicates().sink{[weak self] isStarted inself?.navigationItem.rightBarButtonItem?.title = isStarted ?"Stop":"Start"}.store(in:&cancellables)}@objcprivatefunc tapLeftButton(){
oneway.send(.left)}@objcprivatefunc tapRightButton(){
oneway.send(.right)}@objcprivatefunc tapUpButton(){
oneway.send(.up)}@objcprivatefunc tapDownButton(){
oneway.send(.down)}When creating onewaykit, set the context first.
private lazy varoneway=OneWay<TracerFeature>(
initialState:.init(
position:.init(x: view.center.x, y: view.center.y),
size:.init(width:100, height:100)),
context:TracerViewController.self
)If you want to track actions and state changes, you can use shouldTrace to trace them when sending actions, as shown below:
@objcprivatefunc tapLeftButton(){
oneway.send(.left, shouldTrace:true)}By setting shouldTrace to true, you can observe events that capture the context, action, and how the state changes as a result, as shown below:

First, register the ViewFeature to be used globally and set the initial state.
GlobalOneWay.registerState(feature:GlobalFeature.self, initialState:.init())Then, you can subscribe to and use the state of the desired global feature.
GlobalOneWay.state(feature:GlobalFeature.self)?.map{ $0.backgroundColor }.sink{[weak self]inself?.titleLabel.backgroundColor = $0
}.store(in:&cancellables)You can also send actions to the global feature, of course.
GlobalOneWay.send(feature:GlobalFeature.self,.setBackgroundColor(.white))You can install OneWayKit via Swift Package Manager by adding the following line to your Package.swift:
import PackageDescription
letpackage=Package([...]dependencies:[.package(url:"https: github.com/fomagran/OneWayKit", from:"1.2.0"),])The following projects have greatly inspired the creation of OneWayKit.
Fomagran, fomagran@icloud.com
This library is released under the MIT license. See LICENSE for details.



