Home > OS >  If I use self in the closure, does it cause the memory leaks in Swift?
If I use self in the closure, does it cause the memory leaks in Swift?

Time:10-12

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

  • Related