[RxSwift]UITableViewCellで再利用時の購読が重なるのを防ぐ


前提

RxSwiftでは購読を解除するためにdisposeBagというものがあります。
片や、UITableViewやUICollectionViewのCellには再利用をする機能が実装してあります。
これらを無意識に実装しているとこんなコードになりがちです。

class hogeTableViewCell: UITableViewCell {    
    private var disposeBag = DisposeBag()

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
    }
}

ここで発生する問題点

上記のコードではcellの再利用で購読が重なる可能性が出てきてしまいます。
そのためには、再利用時に適切に購読を解除(破棄)してあげる必要があります。

そこで使用するメソッドがfunc prepareForReuse()です。
これはdequeueReusableCell(withIdentifier:)からオブジェクトを返す直前にこのメソッドを呼び出されるメソッドです。

If a UITableViewCell object has a reuse identifier, the table view invokes this method just before returning the object from the UITableView method dequeueReusableCell(withIdentifier:).

To avoid potential performance issues, you should only reset attributes of the cell that are not related to content, for example, alpha, editing, and selection state.

func prepareForReuse()はパフォーマンスの観点からコンテンツの内容に関係ない属性、例えばアルファ値、エディティングやセレクション状態などのみをリセットすべきと書いてあります。
ですのでここでdisposeBagをセットしてあげることは今回の最適解と言えるでしょう。

after

class hogeTableViewCell: UITableViewCell {    
    private var disposeBag = DisposeBag()

    override func prepareForReuse() {
        super.prepareForReuse()
        self.disposeBag = DisposeBag()
    }
}