L'lynn
L'lynn

Reputation: 177

Deallocation of ViewController

i'm very excited about memory leaks and performance problems with iOS. Currently i've learnt that preventing leaks with getting avoid by retain cycles. I have a snippet below which is containts two viewcontrollers and i'm passing data with delegation. But when i equalized delegate var as nil, the deinit of viewcontroller was not called.

import UIKit

class ViewController: UIViewController, Navigator {


func passData(data: String) {
    print("Passed data: " + data)
}


override func viewDidLoad() {
    super.viewDidLoad()
}

deinit {
    print("deinited: " + self.description)
}

@IBAction func goSecond(_ sender: UIButton) {
    let secondVC = self.storyboard?.instantiateViewController(withIdentifier: "secondVC") as! SecondVC
    secondVC.delegate = self
    self.present(secondVC, animated: false, completion: nil)

}


}

//second vc

import UIKit



protocol Navigator: class{
func passData(data:String)
}

class SecondVC: UIViewController {
weak var delegate:Navigator?
override func viewDidLoad() {
    super.viewDidLoad()
}


@IBAction func GoFirst(_ sender: UIButton) {
   delegate?.passData(data: "I'm second VC and Passing")
   self.delegate = nil

}
}

Upvotes: 3

Views: 6316

Answers (1)

nayem
nayem

Reputation: 7585

You are misunderstood the deinit method's job. The deinit is supposed to be called when the instance of a view controller has no reference left to it. So, just simply removing the references of the properties of a view controller doesn't do the whole job.

And you have a misconception of making self.delegate = nil in your SecondVC. This should have been done in your first ViewController.

To make sense of everything, I've done a sample project where you can learn how deinits work. The main code goes here:

First View Controller

class FirstViewController: UIViewController, Navigator {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    deinit {
        print("First view controller's deinit called")
    }

    func passData(data: String) {
        print("In First view controller: \(data)")
    }

    @IBAction func gotoSecond(_ sender: UIButton) {
        let viewcontroller = storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
        viewcontroller.delegate = self
        show(viewcontroller, sender: self)
    }

}


Second View Controller

protocol Navigator {
    func passData(data:String)
}

class SecondViewController: UIViewController {

    weak var delegate:Navigator?

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    deinit {
        print("Second view controller's deinit called")
    }

    @IBAction func closeButton(_ sender: UIButton) {
        delegate?.passData(data: "Delegation from second view controller")
        dismiss(animated: true, completion: nil)  //when this line executes, the instance of this class is de-referenced. This makes the call to deinit method of this class.
    }
}

So, when dismiss happens for second view controller, the reference count goes to 0 for second view controller and this does the job for calling deinit method of second view controller.

But you technically don't call the deinit of the first view controller as you don't actually de-reference the first view controller.

You can find the whole project here.

Upvotes: 6

Related Questions