Wednesday, December 23, 2020

self in a Swift Self-executing Anonymous Closure

Jesse Squires:

Conclusion: self was just nil the whole time! What a goofy mistake! […] However, that was not the case. Specifically, self was not nil. Not only that, but self wasn’t the self I expected.


Second, why is self an instance of (MyTableCell) -> () -> MyTableCell and not () -> UIButton?


If you declare button as lazy var instead of let, then the expected behavior occurs. That is, self is an instance of MyTableCell within the self-executing anonymous closure and the call to addTarget(_:, action:, for:) works.


The type of self resolving to (MyTableCell) -> () -> MyTableCell is the unfortunate result of the NSObject instance method -[NSObject self] and Swift’s curried functions.


Correcting the expression self (without backticks) to reference the enclosing type introduces another interesting question: what should be order of operations during initialization? When using let, the property is initialized before the enclosing type. When using lazy var, the property is initialized after the enclosing type. I am not a compiler expert, so I will not attempt to answer which is better. But if initialization order cannot be changed in the compiler to fix this, then I think the expected behavior would be to produce the same error as non-NSObject classes: “Cannot find ‘self’ in scope”.


Comments RSS · Twitter

Leave a Comment