why deinit of view controller is not calling using RXSwift?

Viewed 982

I tried a few things but couldn't find a solution. I am navigating the controller in the onNext block but the deinit is not calling. I have also declared the self as weak in the rx closures.

Below is the complete class code. Please correct if I am doing anything wrong:

class LoginVC: UIViewController {

    //MARK:- Variables & Consts
    private let tag = "LoginVC"
    private let loginViewModel = LoginViewModel()
    private let disposeBag = DisposeBag()
    
    //MARK:- IBOutlets
    @IBOutlet weak var tfUsername: MFTextField!
    @IBOutlet weak var tfPassword: MFTextField!
    @IBOutlet weak var btnLogin: UIButton!
    
    //MARK:- View Controller Life Cycle
    override func viewDidLoad() {
        super.viewDidLoad()
        
        setupBindings()
    }
    
    ///deinit
    deinit {
        print(" deinit")
    }
    
    //MARK:- Custom Methods
    
    private func setupBindings() {
        loginViewModel
            .loginResponse
            .observeOn(MainScheduler.instance)
            .subscribe(onNext: { [weak self] loginResponse in
             let vc = UIStoryboard(name: Constants.MAIN, bundle: nil).instantiateViewController(withIdentifier: Constants.HOME_VC)
                self?.navigationController?.pushViewController(vc, animated: true)
            }, onError: { [weak self] error in
                self?.removeLoader()
            }, onCompleted: {  [weak self]  in
                self?.removeLoader()
            }, onDisposed: { [weak self] in
                print("\(self?.tag ?? "") onDisposed")
            })
        .disposed(by: disposeBag)
        
        btnLogin.rx.tap.bind{ [weak self] in
            self?.loginViewModel.login(username: self?.tfUsername.text ?? "", password: self?.tfPassword.text ?? "")
        }.disposed(by: disposeBag)
    }
}

Any help would be appreciated.

2 Answers

You are pushing the next view controller here.

self?.navigationController?.pushViewController

When you do this, LoginVC never gets deallocated because it's still in the memory and navigation controller's stack. So there's no reason for deinit to be called.

deinit will only get called if you dismiss LoginVC. And if your LoginVC is your root viewcontroller it will never call it's deinit. This has nothing to do with RxSwift.

You are strongly capturing self in your observable chain. Then putting the disposable that holds the subscription into a disposeBag that is a property of self.

This means that you have a reference cycle. Your view controller has captured itself in itself.

Related