Search code examples
iosswiftselflazy-initialization

Why this code capturing self inside this block compile in swift?


I work in a project were I came across multiples cases like this,

class ViewController: UIViewController {
   private let clearCacheButton: UIButton = {
       let button = UIButton(type: .custom)
       button.setTitle(AppMessages.General.Action.clearCache.description, for: .normal)
       button.addTarget(self, action: #selector(clearCache), for: .touchUpInside)
       return button
   }()
}

self is being captured to add target for button, yet compiler does not complain about capturing self before initialisation, it works even without lazy var modifier...

Why is that? Is this just a little convenience added by Apple at some point?

If I remember well it was not possible in the past

Thank you for the replies


Solution

  • The compiler has never complained about this. But it should (and I have filed a bug on this point), because the code you've written won't work: the button will not actually do anything when tapped. (The app might even crash, but then again it might not.)

    The reason (for both phenomena) is that the compiler misinterprets the term self here to mean the class — which does exist before initialization of the instance.

    The solution is to replace let by lazy var. That does work, because now the code will not actually be called until some later, when the instance does exist.