9

1つの UIButton に対して2回サブスクライブしています:

  1. クリックごとに UI を更新するための最初のサブスクリプション
  2. 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. からdisposableBagの再初期化を削除しようとしましたprepareForReuse()

    問題は、ボタンへのサブスクリプションが重複して蓄積され、クリックするたびに多くの Web サービス呼び出しが呼び出されることです。

質問:debounceサブスクリプションを最後まで呼び出し、複数のサブスクリプションで繰り返されないように するにはどうすればよいですか ( addDisposableToviewController バッグの場合) ?

4

2 に答える 2

7

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 イベント ( onNextonErroronCompletedonSubscribedおよび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)

View Controllerのを使用DisposeBagすることで、セルが破棄されても(下にスクロールしたときに)操作が継続されることを確認できます。ただし、セルが破棄されたときにサブスクリプションを破棄する必要がある場合はDisposeBag、View Controller ではなく、セルの を使用してください。

補足 - メモリリーク

selfメモリ リークの発生を防止できるように、への参照が弱いように指定されていることに注意してください。弱いと指定することで、オプションの自己への参照が提供されます。

これを行わないと、ブロック用に作成したクロージャーは、あなたonNextの への強い参照を保持し、selfこれは、UICollectionViewCell私たちが議論しているまさにそのクロージャーを所有します。

これにより、最終的にメモリ不足によるクラッシュが発生します。誤って自己を参照することによって引き起こされるメモリ リークについて詳しくは、質問のコメントに投稿したリファレンスを参照してください。

于 2017-04-04T16:20:02.607 に答える