Reputation: 177
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
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