RxRelayed is a lightweight Swift Property Wrapper that eliminates boilerplate code when using BehaviorRelay and Driver in RxSwift. It allows you to handle state as a standard property while maintaining the power of reactive streams.
- Zero Boilerplate: No more manual
_relayandasDriver()declarations. - Property-like Syntax: Mutate and access values directly using the
=operator. - Automatic Projection: Access the
Driverstream instantly using the$prefix. - Thread-Safe: Built on top of
BehaviorRelayfor safe state management.
Add the following to your Package.swift file:
dependencies: [
.package(url: "https://github.com/mandooplz/RxRelayed.git", branch: "main")
]Then add RxRelayed to your target's dependencies:
targets: [
.target(
name: "YourTarget",
dependencies: [
"RxRelayed"
]
)
]Simplify your state declarations using the @Relayed wrapper.
import RxRelayed
final class UserViewModel {
// Declares a BehaviorRelay with an initial value
@Relayed var userName: String = "Guest"
@Relayed var isVip: Bool = false
func updateName(to newName: String) {
// Direct mutation (calls .accept() internally)
userName = newName
}
}Use the $ prefix to access the Driver for UI binding.
import RxSwift
import RxCocoa
final class UserViewController: UIViewController {
private let viewModel = UserViewModel()
private let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
// Use '$' to bind the projected Driver
viewModel.$userName
.drive(nameLabel.rx.text)
.disposed(by: disposeBag)
viewModel.$isVip
.drive(vipBadge.rx.isHidden.map { !$0 })
.disposed(by: disposeBag)
}
}- iOS 13.0+
- Swift 5.9+
- RxSwift 6.0+