Nick
Nick

Reputation: 479

How to get change the value of the UISlider

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

Answers (3)

Daniel T.
Daniel T.

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

SoftDesigner
SoftDesigner

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

xandrefreire
xandrefreire

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

Related Questions