在UICollectionViewCell - RxSwift 3中使用rx.tap的UIButton的问题



我订阅了 2 次 1 UIButton :

  1. 首次订阅,用于在每次点击时更新 UI
  2. 第二个订阅,用于在累积单击后每 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服务调用将被释放并且不会更新。

我尝试过的:

  1. addDisposableTo(vc?.rx_disposableBag)添加到父 ViewController DisposableBag。

    问题,订阅累积和每次点击时updateWS()调用多次,这些在每个滚动上订阅并且从未处理过。

  2. 我试图从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 事件(onNextonErroronCompletedonSubscribedonDisposed)都会触发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,而又拥有我们正在讨论的闭包。

这最终会导致内存不足崩溃。请参阅我在您的问题评论中发布的参考资料,以获取有关错误引用自我引起的内存泄漏的更多内容。

最新更新