我订阅了 2 次 1 UIButton :
- 首次订阅,用于在每次点击时更新 UI
- 第二个订阅,用于在累积单击后每 1 秒更新一次 Web 服务上的值。
法典:
class ProductionSize {
var id : Int?
var size: Int = 0
var name: String = ""
}
class ProductionCell: UICollectionViewCell {
var rxBag = DisposeBag()
// this will be set in the (cellForItemAt indexPath: IndexPath) of collection view
var productionSize: ProductionSize? {
didSet {
showProductionSize()
prepareButton()
}
}
func showProductionSize() {
// ... code for showing ProductionSize in labels
}
func prepareButton() {
// This for subscribing for every click for displaying purpose
btn_increase.rx.tap
.subscribe(){event in
self.increaseClicked()
}
.addDisposableTo(rxBag)
// this for subscribing for sending webservice request after 1 second of clicking the button (so that if user click it quickly i send only last request)
btn_increase.rx.tap
.debounce(1.0, scheduler: MainScheduler.instance)
.subscribe(){ event in self.updateOnWS() }
.addDisposableTo(rxBag)
}
func increaseClicked() {
productionSize.size = productionSize.size + 1
showProductionSize()
}
func updateOnWS() {
// code for updating on webservice with Moya, RxSwift and Alamofire§
}
// when scrolling it gets called to dispose subscribtions
override func prepareForReuse() {
rxBag = DisposeBag()
}
}
问题:
由于处置发生在prepareForReuse()
,如果我多次单击按钮并立即滚动,则Web服务调用将被释放并且不会更新。
我尝试过的:
将
addDisposableTo(vc?.rx_disposableBag)
添加到父 ViewController DisposableBag。问题,订阅累积和每次点击时
updateWS()
调用多次,这些在每个滚动上订阅并且从未处理过。我试图从
prepareForReuse()
中删除一次性包重新初始化。问题,再次对按钮的订阅被复制和累积,并且每次单击都会调用许多Web服务调用。
问:如何才能将debounce
订阅调用到最后,并且永远不会重复多个订阅(在 viewController BagaddDisposableTo
的情况下)?
由于prepareButton()
总是在集合视图的(cellForItemAt indexPath:IndexPath)中调用,因此您可以尝试以下操作:
func prepareButton() {
self.rxBag = nil
let rxBag = DisposeBag()
// This for subscribing for every click for displaying purpose
btn_increase.rx.tap
.subscribe(onNext: { [weak self] _ in
self?.increaseClicked()
})
.addDisposableTo(rxBag)
// this for subscribing for sending webservice request after 1 second of clicking the button (so that if user click it quickly i send only last request)
btn_increase.rx.tap
.debounce(1.0, scheduler: MainScheduler.instance)
.subscribe(onNext: { [weak self] _ in
self?.updateOnWS()
})
.addDisposableTo(rxBag)
self.rxBag = rxBag
}
删除prepareForReuse()
实现。
addDisposableTo(vc?.rx_disposableBag)
添加到父 ViewController DisposableBag。问题,订阅累积,每次单击时 updateWS() 调用多次,每次滚动都订阅并且从未处理过。
由于您订阅按钮点击的方式,您的self.updateOnWS()
可能会被多次调用。
btn_increase.rx.tap
.debounce(1.0, scheduler: MainScheduler.instance)
.subscribe(){ event in self.updateOnWS() }
.addDisposableTo(rxBag)
如您所见,您使用subscribe()
方法订阅所有事件。这意味着所有 Rx 事件(onNext
、onError
、onCompleted
、onSubscribed
和onDisposed
)都会触发self.updateOnWS()
。您可以通过打印出event
对象来检查是否是这种情况,以查看触发了什么事件。
仅在onNext
上订阅
可能的解决方法可能是仅订阅onNext
操作。
btn_increase.rx.tap
.debounce(1.0, scheduler: MainScheduler.instance)
.subscribe(onNext: { [weak self] (_ : Void) in
self?.updateOnWS()
})
.addDisposableTo(vc?.rxdisposableBag)
通过使用视图控制器的DisposeBag
,您可以确保即使单元格被释放(向下滚动时),操作仍会继续。但是,如果在释放单元时需要它来释放订阅,请使用单元的DisposeBag
,而不是视图控制器。
旁注 - 内存泄漏
请注意,对self
的引用被指定为弱引用,以便可以防止发生内存泄漏。通过将其指定为弱,它将为您提供对可选的 self 的引用。
如果不这样做,您为onNext
块创建的闭包将保留对self
的强引用,这是您的UICollectionViewCell
,而又拥有我们正在讨论的闭包。
这最终会导致内存不足崩溃。请参阅我在您的问题评论中发布的参考资料,以获取有关错误引用自我引起的内存泄漏的更多内容。