0

Does a UIAlertAction's handler need a [weak self] or [unowned self] to avoid a retain cycle, or is it fine to keep it as a strong reference?

e.g.

extension UIViewController {
    func showAlert() {
        let alert = UIAlertController(
            title: "Foo",
            message: "Bar",
            preferredStyle: .alert
        )
        alert.addAction(
           .init(
               title: "OK",
               style: .default
           ) {
               self.doSomething()
           }
        )
        present(alert, animated: true)
     }
}

The handler closure retains self. alert is never explicitly retained by self, but does self retain it implicitly because of the call to present? How would you determine whether that is the case? Maybe this uncertainty is sufficient justification for not using a strong reference…

I know when I should use unowned versus when to use weak. My question is about including either of those two versus including nothing, i.e. keeping it as a strong reference. There are lots of blog posts and questions about this but most of them focus on weak versus unowned and don't really expand on when you don't need to use either of them.

I know practically you could just always put [weak self] everywhere and it's not really a performance concern. But I'm trying to understand when it's really necessary and when it is just noise. Using an alert as an example here, but I'm interested in developing a sense for this in general as well so I can justify myself when I choose to include or exclude a [weak self] or [unowned self].

Is a retain cycle the only concern with strongly referencing self inside a closure?

shim
  • 9,289
  • 12
  • 69
  • 108
  • A nice explanation, it could help you to understand the proper use of `[weak self]` & `[unowned self]` http://www.andrewcbancroft.com/2015/05/08/strong-weak-and-unowned-sorting-out-arc-and-swift/ – Tulon Nov 09 '22 at 09:30

1 Answers1

3

The alert, it's true, has a strong reference to self. But self has no strong reference to the alert! It just makes the alert, presents it, and drops it. Therefore there is no retain cycle.

The alert, as long as it is showing, continues to retain self and prevents it from going out of existence. But self should not go out of existence while the alert is showing, so that's okay too.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • How does one know that `present` doesn't retain the controller that is passed to it? Is that just obvious? Or perhaps iOS just doesn't things like that? etc Who is holding onto the presented view controller if not the presenter? The window? – shim Nov 09 '22 at 03:49
  • 1
    `present` does hold on to the presented view controller. That's why I said that while the presentation is going on, sure, self is being retained. There is a possible cycle at that moment. But it's unimportant. The alert controller will be released when it is dismissed, and so all will be well. – matt Nov 09 '22 at 03:56
  • So if the situations was changed, and it was a subview of the view controller which had some closure which strongly referenced the view controller, then that would be a memory leak? – shim Nov 09 '22 at 17:07
  • I don't see what that has to do with alerts. – matt Nov 09 '22 at 17:22
  • Nothing really… "Using an alert as an example here, but I'm interested in developing a sense for this in general as well" I could ask this as a separate SO question if you prefer… just want to figure out when you would have a retain cycle, unlike this situation. – shim Nov 09 '22 at 17:26
  • You don't have to think (though thinking is useful). Just looking is enough. You'll know if you have a retain cycle because the view controller (or whatever) won't `deinit` when you expect it to. – matt Nov 09 '22 at 18:10