1
votes

I inherited a project that uses disposeBags everywhere, but disposeBag seems to be a massive memory leak. None of the view controllers utilizing the bag ever get deallocated, which leads to subscriptions piling up. I'm

class TestViewController: UIViewController 
{

    @IBOutlet weak var testLabel: UILabel!
    var basePresenter: BasePresenter = BasePresenter()
    var disposeBag: DisposeBag = DisposeBag()
    override func viewDidLoad() {
        super.viewDidLoad()
        bindPresenter()
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        //self.disposeBag = DisposeBag()                 <------------
    }

    func bindPresenter() {
        //super.bindPresenter()
        basePresenter.testVariable.asDriver().drive(onNext: { test in
            if !test.id.isEmpty {
                self.testLabel.text = "Test text"      //<------------
            }
        }).addDisposableTo(disposeBag)
    }

    deinit{
        print("TestView was dealloc'd")
    }
}

The key issue is the reference in the handler to "self."
My theory is that self is a strong reference, which is leading to a situation where even when the view controller gets popped and there are no other references to the view controller, it still doesn't get deallocated because the bag has a strong reference to it. Circular logic where the bag doesn't get disposed because the VC doesn't dealloc and the VC doesn't dealloc because the bag doesn't get disposed.

The commented out line

//self.disposeBag = DisposeBag()

when called allows for the view to properly dealloc.

On top of the memory leak, the issue that I'm facing is that I don't want to dispose the bag on viewWillDisappear, but rather when the view is popped. I need it to stick around if I add a view on top in case I pop back to this view.

Any help would be greatly appreciated!

1
By the way, it isn't just references to UI elements, if I referred to a variable self.testString instead of self.testLabel.text, it would still result in the VC not being disposedMars

1 Answers

2
votes

Your theory is correct. You need to use a weak or unowned reference to self in your subscribe methods rather than a strong reference. And get rid of the assignment to disposeBag in the viewWillDissapear. The disposeBag will properly dispose of your subscribers when the object gets deinted.

You setup a weak reference to self like this:

   basePresenter.testVariable.asDriver().drive(onNext: { [weak self] test in
        if !test.id.isEmpty {
            self?.testLabel.text = "Test text" // no longer a strong reference
        }
    }).disposed(by: disposeBag)