Search code examples
swiftrealmrx-swiftrx-cocoa

Driver is being triggered constantly between View Model and View Controller


Have an issue with a Driver on RxSwift. Have a view model who is listening to an initTrigger in a ViewController as follow.

    let initTrigger = rx.viewWillAppear
                .mapToVoid()
                .asDriverOnErrorJustComplete()

This initTrigger is used to bind to another Driver on the view model


    let shoppingCart: Driver<ShoppingCart>

    let shoppingCart = input.initTrigger
                .flatMapLatest {
                    self.getShoppingCartUseCase
                        .execute()
                        .asDriver(onErrorJustReturn: ShoppingCart())
                }

getShoppingCartUseCase.execute() returns Observable<ShoppingCart> and is using RxRealm lo listen to changes to a database.

back on the view controller, I have subscribed to that shoppingCart like this

        output?.shoppingCart
            .map {
                print("Mapping")
                return $0.lines.count == 0
            }
            .asObservable()
            .bind(to: goToCartButton.rx.isHidden)
            .disposed(by: bag)

I placed the print("Mapping") to realize that this last Driver is being triggered constantly after making an action that modifies my model and triggers the Observable<ShoppingCart> I mentioned before.

What I'm doing wrong here?

Thanks for your help.


Solution

  • First of all you can use .distincUntilChanged() to filter identical events. second of all, check why .getShoppingCartUseCase keeps on emitting events, RxRealm will send updates whenever ShoppingCart is written to the db, so maybe you have some unnesessary writes. make sure when you write to realm you use .modified flag, not .all (which will override an item only if it has changed, and won't cause event if it hasn't)

    If you sure you only need to an event once - you can always add .take(1) Also you call it initTrigger, but send it on viewWillAppear - which can be called as many times as you getting back to the screen. If you need it once, put it on viewDidLoad

    PS instead of .asObservable().bind(to:...) you can just write .drive(...) which is cleaner way to bind drivers to ui.