I'm new to Automatic reference counting and memory leaks and have (maybe) simple questions about them.
Now I get the general idea of what ARC thinks and how to avoid memory leaks, and my question is if a function has closure and requires to use self in that block, do I always need to write [weak self]
to avoid the memory leaks?
For example...
I just made a class called ViewControllerA, and it has a function, showDeleteAlert, which delete item by the target index and target id. (sorry it's just a random class and function). In the showDeleteAlert function's delete action, there is a closure to access dataSource class's delete function. I thought I need to use [weak self]
in the closure, since the ViewControllerA has a strong reference to showDeleteAlert function and showDeleteAlert function use self in the closure, which I think it has a strong connection to the ViewControllerA. Therefore, I put the [weak self]
to avoid memory leaks. In that case, do I need a weak self in the closure? (if not, could you explain why I don't need a weak self please?)
class ViewControllerA: UIViewController {
private var dataSource = MyDataSource()
private var targetIndex = Int()
private var targetId = String()
func showDeleteAlert() {
let deleteAction = UIAlertAction(title: "DELETE", style: .destructive) { [weak self] _ in
guard let strongSelf = self else {
return
}
strongSelf.dataSource.delete(by: strongSelf.targetId, at: strongSelf.targetIndex, completion: strongSelf.reloadVC)
}
let cancelAction = UIAlertAction(title: Alert.ButtonTitle.cancel, style: .cancel)
self.showAlert(title: alertTitle, message: nil, actions: [deleteAction, cancelAction], style: .actionSheet, completion: nil)
}
func reloadVC() {
// do something for reload VCA
}
}
CodePudding user response:
Answer depends on your implementation of MyDataSource
and showAlert(title:
method for which you haven't added any implementation details, assuming its not doing anything irrational answer mostly is NO you dont need [weak self]
Memory leak happens only when there is a cyclic reference causing the deadlock situation between two objects in the memory, stopping both of them being removed/purged from memory.
Just because you use a closure, you need not necessarily use [weak self]
in closures capture list as long as you know there is no circular dependency or in other words cyclic reference.
Let's analyse it:
In your case you access dataSource
, targetIndex
,targetId
and call an instance method reloadVC
as well from closure, that means, unless you specify [weak self]
or [unowned self]
closure will hold a strong reference to self
Obviously your self
holds a strong reference to dataSource
and other instance properties, assuming your dataSource
does not hold a strong reference to self
(Cant really imagine a use case where data source holds a strong reference to self) dependency graph is not cyclic in anyway
A reference graph will be like
Closure -> Self -> Data Source
If your Data Source itself holds a strong reference to Self
then graph will be cyclic
Closure -> Self -> Data Source -> Self
Or if your Self
holds a strong reference to your UIAlertController
or to your UIAlertAction
UIAlertController -> Closure -> self -> UIAlertController
UIAlertController -> UIAlertAction -> Closure -> self -> UIAlertAction
Thats why I mentioned that answer depends on your implementation of showAlert(title:
method
Assuming you are not doing anything irrational (sorry couldnt come up with rational reasoning as to why one would hold strong reference to UIAlertController
or UIAlertAction
), I dont see any cyclic reference being formed hence no deadlock hence no memory leak.
Additional info
Assuming there is some kind of cyclic dependency and you wanna avoid memory leak, in this specific case you might wanna use [unowned self]
instead of [weak self]
If you aren't sure of difference between [weak self]
and [unowned self]
do read
Shall we always use [unowned self] inside closure in Swift
Hope it helps