Search code examples
iosswiftrx-swift

How to ignore behaviorRelay element removal on RxSwift?


I'm observing a BehaviorRelay and I want to subscribe only when the number of items increase. I tried distinct/dinstinctUntilChanged but it does not suit my needs because it will skip too much or too few times.

behaviorRelay
  .compactMap { $0?.items }
  .subscribe(onNext: { elements in
      print("items has one more element.")
  }).disposed(by: bag)

var behaviorRelay = BehaviorRelay<[Car]?>(value: [])

class Car {
  var items: [Any] // whatever... just an example.
}

Solution

  • First of all, use map to map from array to number (of elements):

    .map { $0?.count ?? 0 } // return 0 if array is nil
    

    Than use scan, to retrieve both current and previous element, like this:

    .scan((0, 0)) { previousPairOfValues, newValue in
        return (previousPairOfValues.1, newValue) // create new pair from newValue and second item of previous pair
    }
    

    Then use filter, to only pass increasing values:

    .filter { $0.1 > $0.0 } // newer value greater than older value
    

    Than map it back to the latest value:

    .map { $0.1 }
    

    Putting all together:

    behaviorRelay
      .compactMap { $0?.items }
      .map { $0?.count ?? 0 } // return 0 if array is nil
      .scan((0, 0)) { previousPairOfValues, newValue in
        return (previousPairOfValues.1, newValue) // create new pair from newValue and second item of previous pair
      }
      .filter { $0.1 > $0.0 } // newer value greater than older value
      .map { $0.1 }
      .subscribe(onNext: { elementCount in
          print("items has one more element.")
          print("there are \(elementCount) items now")
      }).disposed(by: bag)