View Model 和 View Controller 之间不断触发驱动程序

Driver is being triggered constantly between View Model and View Controller

RxSwift 上的 Driver 有问题。在 ViewController 中有一个正在监听 initTrigger 的视图模型,如下所示。

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

initTrigger 用于绑定到视图模型上的另一个 Driver


    let shoppingCart: Driver<ShoppingCart>

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

getShoppingCartUseCase.execute() returns Observable<ShoppingCart> 并且正在使用 RxRealm 来监听数据库的变化。

回到视图控制器,我已经订阅了 shoppingCart 像这样

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

我放置 print("Mapping") 是为了意识到在执行修改我的模型并触发我之前提到的 Observable<ShoppingCart> 的操作后,最后一个驱动程序会不断被触发。

我哪里做错了?

感谢您的帮助。

要停止订阅观察者必须执行以下操作之一:

  1. 发送错误信息

  2. 发送完成的消息

  3. 销毁订阅(销毁disposeBag)

在你的情况下 rx.viewWillAppear 也不会 shoppingCart 不发送错误或完成的消息,因为它们是驱动程序

您正确停止订阅的一种方法是销毁旧的 disposeBag bag = DisposeBag()

但不要忘记在 viewWillAppear 上恢复订阅

其他选项 将在 VC 中有一些标志,例如

var hasAppeared: Bool

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    ...
    hasAppeared = true
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisppear(animated)
    ...
    hasAppeared = false
}

并且只是为了添加过滤

    output?.shoppingCart
        .filter({ [weak self] _ in self?.hasAppeared ?? false })
        .map {
            print("Mapping")
            return [=11=].lines.count == 0
        }
        .asObservable()
        .bind(to: goToCartButton.rx.isHidden)
        .disposed(by: bag)

第三种方式是停止从viewModel内部发送

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


let shoppingCart: Driver<ShoppingCart>

let shoppingCart = Observable.merge(input.initTrigger.map({ true }), 
                                    input.stopTrigger.map({ false }))
            .flatMapLatest { isRunning in
                guard isRunning else {
                    return .just(ShoppingCart())
                }

                return self.getShoppingCartUseCase
                    .execute()
                    .asDriver(onErrorJustReturn: ShoppingCart())
            }

首先你可以使用.distincUntilChanged()来过滤相同的事件。 其次,检查为什么 .getShoppingCartUseCase 不断发出事件,只要 ShoppingCart 被写入数据库,RxRealm 就会发送更新,所以也许你有一些不必要的写入。确保当你写入领域时使用 .modified 标志,而不是 .all (只有当项目发生变化时才会覆盖它,如果没有变化则不会引起事件)

如果您确定只需要参加一次活动 - 您可以随时添加 .take(1) 你也称它为 initTrigger,但在 viewWillAppear 上发送它——当你返回屏幕时可以调用它多次。如果你需要一次,把它放在viewDidLoad

PS 而不是 .asObservable().bind(to:...) 你可以只写 .drive(...) 这是将驱动程序绑定到 ui.

的更简洁的方法