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()
返回Observable<ShoppingCart>
,并且正在使用RxRealm监听对数据库的更改。
回到视图控制器,我已经像这样订阅了shoppingCart
output?.shoppingCart
.map {
print("Mapping")
return $0.lines.count == 0
}
.asObservable()
.bind(to: goToCartButton.rx.isHidden)
.disposed(by: bag)
我放置了print("Mapping")
,以意识到在执行修改我的模型并触发我之前提到的Observable<ShoppingCart>
的动作之后,最后一个Driver一直在被触发。
我在这里做错了什么?
感谢您的帮助。
答案 0 :(得分:1)
首先,您可以使用.distincUntilChanged()
过滤相同的事件。
其次,检查为什么.getShoppingCartUseCase
继续发出事件,每当将ShoppingCart写入数据库时,RxRealm都会发送更新,因此也许您有一些不必要的写入。确保在写入领域时使用.modified
标志,而不是.all
(仅当项目更改时,它才会覆盖项目,如果没有更改,则不会导致事件)
如果确定只需要一次活动-您可以随时添加.take(1)
您也可以将其称为initTrigger
,但可以通过viewWillAppear
发送它-返回屏幕后可以调用多次。如果需要一次,请将其放在viewDidLoad
PS代替.asObservable().bind(to:...)
,您只需编写.drive(...)
,这是将驱动程序绑定到ui的更简便方法。
答案 1 :(得分:0)
要停止订阅观察者,必须执行以下操作之一:
发送错误消息
发送完成的消息
处置订阅(销毁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 $0.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())
}