Reputation: 479
How to get the values while moving the UISlider?
I'm using the following code:
ViewModel:
import Foundation
import RxSwift
final class ViewModel {
private let disposeBag = DisposeBag()
var value: Variable<Float>
init() {
self.value = Variable(Float(0.0))
}
}
ViewController:
@IBOutlet var slider: UISlider!
private var viewModel: ViewModel!
private let disposeBag = DisposeBag()
override func viewDidLoad() {
viewModel = ViewModel()
slider.rx.value
.subscribe(onNext: { (value) in
self.viewModel.value = Variable(Float(value))
})
.addDisposableTo(disposeBag)
}
But this code does not work. What's my mistake?
Upvotes: 4
Views: 6269
Reputation: 33979
You're replacing the Variable instead of inserting a new value into it. This is guaranteed to fail.
ViewModel.value
should be a let
instead of a var
. You don't want to replace Variable, you want to assign a new value into it. While you are at it, make your ViewModel a struct:
struct ViewModel {
let value = Variable<Float>(0)
}
It can be a final class if you must, but value
should still be a let
not a var
.
Your viewDidLoad
should look like this:
public override func viewDidLoad() {
super.viewDidLoad()
slider.rx.value
.subscribe(onNext: { [weak self] value in
self?.viewModel.value.value = value
})
.disposed(by: disposeBag)
}
Or better yet:
public override func viewDidLoad() {
super.viewDidLoad()
slider.rx.value
.bind(to: viewModel.value)
.disposed(by: disposeBag)
}
Or even better... Whatever is subscribing to ViewModel.value should subscribe/bind directly to slider.rx.value instead. That way you can get rid of the middleman.
Something like this:
public class ViewController: UIViewController {
@IBOutlet weak var slider: UISlider!
@IBOutlet weak var label: UILabel!
private let disposeBag = DisposeBag()
public override func viewDidLoad() {
super.viewDidLoad()
slider.rx.value
.map { "The slider's value is \($0)" }
.bind(to: label.rx.text)
.disposed(by: disposeBag)
}
}
You will see the label's text change as you move the slider.
Upvotes: 7
Reputation: 5853
If you use new BehaviorRelay
instead of old Variable
:
struct MyViewModel {
let value = BehaviorRelay<Float>(value: 0)
}
class ViewController: UIViewController {
@IBOutlet var slider: UISlider!
@IBOutlet var valueLabel: UILabel!
private var viewModel = MyViewModel()
override func viewDidLoad() {
super.viewDidLoad()
slider.rx.value
.bind(to: viewModel.value)
.disposed(by: rx.disposeBag)
// If you want to listen and bind to a label
viewModel.value.asDriver()
.map { "Value: \($0 * 100)%" }
.drive(valueLabel.rx.text)
.disposed(by: rx.disposeBag)
}
}
Upvotes: 3
Reputation: 2326
Not tested, but I would try:
override func viewDidLoad() {
viewModel = ViewModel()
slider.rx.value
.subscribe(onNext: { (value) in
self.viewModel.value.value = Float(value)
})
.addDisposableTo(disposeBag)
}
Also I would rename your value
property in your viewModel
to sliderValue
(or whatever, but not value
). If you do this, your code will look better:
self.viewModel.sliderValue.value = Float(value)
instead of
self.viewModel.value.value = ...
Upvotes: 4