I am subscribing 2 times for 1 UIButton :
Code:
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()
}
}
The problem:
Since the dispose happens on prepareForReuse()
, If i click on the button many times and scroll immediately, the webservice calls gets disposed and not updated.
what I have tried:
Added addDisposableTo(vc?.rx_disposableBag)
to the parent ViewController DisposableBag.
The problem, the subscribtions accumulated and on every click the updateWS()
called many times which is subscribed on every scroll and never disposed.
I have tried to remove the disposableBag re-initialization from prepareForReuse()
.
The problem, Again the subscriptions to the buttons getting duplicated and accumulated and many webservice calls get called every click.
Question:
How can I get the debounce
subscriptions called to the end and never repeated with multiple subscriptions (in case of addDisposableTo
viewController Bag) ?
Since prepareButton()
is always called in the (cellForItemAt indexPath: IndexPath) of collection view you could try this:
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
}
Remove the prepareForReuse()
implementation.
Added
addDisposableTo(vc?.rx_disposableBag)
to the parent ViewController DisposableBag.The problem, the subscribtions accumulated and on every click the updateWS() called many times which is subscribed on every scroll and never disposed.
It is possible that your self.updateOnWS()
gets called many times because of how you subscribe to the button's tap.
btn_increase.rx.tap
.debounce(1.0, scheduler: MainScheduler.instance)
.subscribe(){ event in self.updateOnWS() }
.addDisposableTo(rxBag)
As you can see, you subscribe to all events using the subscribe()
method. This means that all Rx events (onNext
, onError
, onCompleted
, onSubscribed
, and onDisposed
) trigger the self.updateOnWS()
. You can check if this is the case by printing out the event
object to see what event was triggered.
onNext
onlyA possible fix might be to only subscribe to the onNext
operation.
btn_increase.rx.tap
.debounce(1.0, scheduler: MainScheduler.instance)
.subscribe(onNext: { [weak self] (_ : Void) in
self?.updateOnWS()
})
.addDisposableTo(vc?.rxdisposableBag)
By using the DisposeBag
of the view controller, you can make sure that the operation still continues even if the cell gets disposed (when you scroll down). However, if you need it to dispose the subscription when the cell gets disposed, use the DisposeBag
of the cell, not the view controller.
Notice that the reference to self
is specified to be weak, so that you can prevent memory leaks from happening. By specifying it to be weak, it will provide you a reference to self that is optional.
Without doing this, the closure you created for the onNext
block will retain a strong reference to the self
which is your UICollectionViewCell
, which in turn owns the very closure we are discussing.
This will eventually cause a out of memory crash. See the reference I posted on the comments of your question for more things to read about memory leaks caused by incorrectly referencing self.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With