Search code examples
swiftreactive-programmingobservablepublish-subscriberx-swift

How to use a Publish subject to observe a variable's value?


I'm new to using RxSwift framework, I'm actually learning and trying to understand the basics and I would like some help from you please.

private func observeCurrentIndex() -> Observable<Int> {
    return Observable<Int>.create { (observer) -> Disposable in
      observer.onNext(self.currentIndex)
      return Disposables.create()
    }
  }

Here I've created an observable on currentIndex which is an int. When I subscribe to it, I get only the first value of currentIndex which is 2. Is it not supposed to notify me whenever currentIndex changes(just like a KVO would)?

override func viewDidLoad() {
    super.viewDidLoad()
    observeCurrentIndex()
      .subscribe(onNext: { (valeur) in
        print("new value \(valeur)")
      })
      .addDisposableTo(disposeBag)
  }

To be notified each time currentIndex changes value, I've been told that I have to use a publishSubject for that.

@IBAction func increaseAction(_ sender: UIButton) {
    if currentIndex <= kMaxIndex {
      currentIndex = currentIndex + 1
    }
  }

Could someone indicate to me where and how to do this? Thanks in advance.


Solution

  • Usually, Subjects are used to bridge an imperative API to reactive world. More information on how to use subject can be found here.

    There are a couple solution to observe a variable evolution using RxSwift's primitives

    Using KVO

    class WithIndex: NSObject {
      dynamic var currentIndex: Int
    
      func observeCurrentIndex() -> Observable<Int> {
        return instance.rx.observe(Int.self, "currentIndex")
      }
    
      @IBAction func increaseAction(_ sender: UIButton) {
        if currentIndex <= kMaxIndex {
          currentIndex = currentIndex + 1
        }
      }
    }
    

    The drawback with this solution is that WithIndex needs to inherit from NSObject for KVO to be available.

    Using Variable

    class WithIndex {
      let currentIndex: Variable<Int>
    
      func observeCurrentIndex() -> Observable<Int> {
        return currentIndex.asObservable()
      }
    
      @IBAction func increaseAction(_ sender: UIButton) {
        if currentIndex.value <= kMaxIndex {
          currentIndex.value = currentIndex.value + 1
        }
      }
    }
    

    This one is more pratical. You can then set currentIndex's value using currentIndex.value = 12 and observe using currentIndex.asObservable().subscribe(...).

    Variable is a simple wrapper around BehaviorSubject and will send a .next event every time variable's value changes.