Reputation: 1527
I have created a simple flow to test memory in ios app. I have two view controllers in a navigation stack. I am showing an alert in the first view controller to allow user to move to the next one. Following is the code I am using.
class ViewController: UIViewController {
@IBOutlet weak var labelInfo: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func showNextScreen(_ sender: Any) {
let alert = UIAlertController(title: "Alert", message: "Go to next screen?", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Yes", style: .default, handler: { [unowned self] (action) in
self.performSegue(withIdentifier: "showNextScreen", sender: nil)
}))
alert.addAction(UIAlertAction(title: "No", style: .default, handler: { [unowned self] (action) in
self.labelInfo.text = "You did not move to next screen"
alert.dismiss(animated: true, completion: nil)
}))
self.present(alert, animated: true, completion: nil)
}
}
Having gone through the resources mentioning that there should not be a strong reference cycle, I have used unowned self in the code. Checking the leaks in the Instruments, I got the following graph.
The graph shows no leaks as indicated by green tick marks. However, as I move back and froth between the two view controllers, the memory usage graph is being increased. What might be causing this increase in memory usage (first question)?
Next, I also checked the effects replacing unowned self with self. The result I got is the same as before. This suggests there is no strong reference. How do we determine existence of strong retain cycle with reference to this example (second question)?
Upvotes: 4
Views: 3562
Reputation: 908
Go to Edit Scheme -> Run -> Diagnostics
Now tick Malloc stack
like the screenshot. After doing that, rebuild and run . Now open
Debug memory graph
, you will see purple icon on the list of your class where memory leak has occurred. see this screenshot Example Repo with memory leak is Swift Memory Leak Demo Here is the view for memory leak with real example with the attached repo
You can follow the same procedure on your project to identify the memory leak
Upvotes: 4
Reputation: 5088
Starting from your second question.
With instruments aside, your code is segueing a UIViewController
and dismiss it if simple as that, let us not think about retain cycles just yet.
1- Usually, when a property is being created, the reference is strong unless they are declared weak or unowned.
2- With the property labelled as weak, it will not increment the reference count
3- An unowned reference falls in between, they are neither strong nor or type optional Compiler will assume that object is not deallocated as the reference itself remain allocated.
What is retain cycle:
Unless there is some other reference to the parent or child, they both become orphaned. But the retain cycle between the parent and child prevent either from being released and they become wasted memory.
A child should never retain a parent. If anything, use a weak reference in the child to maintain a reference to the parent.
Now lets take a look on what you have, you are using UINavigationController & segue
, well the UINavigationController
is a LIFO stack, also according to apple
A navigation controller is a container view controller that manages one or more child view controllers in a navigation interface. In this type of interface, only one child view controller is visible at a time.
So checking your UIViewController
deinit
function i think you would have no problem telling that the reference deallocated.
Now lets try to look to something else in the UIAlertAction
you have this [unowned self]
.
When to use unowned self or weak self
The only time where you really want to use [unowned self] or [weak self] is when you would create a strong reference cycle. A strong reference cycle is when there is a loop of ownership where objects end up owning each other (maybe through a third party) and therefore they will never be deallocated because they are both ensuring that each other stick around.
In the specific case of a closure, you just need to realize that any variable that is referenced inside of it, gets "owned" by the closure. As long as the closure is around, those objects are guaranteed to be around. The only way to stop that ownership, is to do the [unowned self] or [weak self]. So if a class owns a closure, and that closure captures a strong reference to that class, then you have a strong reference cycle between the closure and the class. This also includes if the class owns something that owns the closure.
And as you said switching both [unowned self]
and [self]
did nothing.
Now the first question,
Well instruments leak checks are simple its a simply compare the significant increases in memory in the period of time, and compares it all to each others based on whats going on, this is not a 100% description but close, so whenever that green tick pops up it means you passed the test. doesn't mean 100% you are safe yet, you can visually see the allocation in the bottom section of instrument, observe the values changes (increasing/ decreasing) .. if something in increasing without ever decreasing, i think you found you problem.
Looking into your case i don't think you would find one
Upvotes: 2