Search code examples
iosswiftuilabelswift4uitapgesturerecognizer

Why does UILabel TapGesture only work after label initialization?


I have the following code to initialize a label:

let forgotPasswordLabel: UILabel = {
        let label = UILabel()
        label.text = "Forgot password?"
        label.font = ApplicationScheme.instance.containerScheme.typographyScheme.subtitle1
        label.textColor = ApplicationScheme.instance.containerScheme.colorScheme.onPrimaryColor
        label.textAlignment = .right
        label.sizeToFit()
        label.accessibilityRespondsToUserInteraction = true
        label.isUserInteractionEnabled = true
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

And later on I add it to the subview as such:

let passwordLabel = forgotPasswordLabel
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(onForgotPasswordClick))
passwordLabel.addGestureRecognizer(tapGesture)
self.view.addSubview(passwordLabel)

If I do the code as such then it works fine, however if I put the tapGesture code inside the label forgotPasswordLabel initialization, the tap gesture does not fire. Why is that?

Code that does not work:

let forgotPasswordLabel: UILabel = {
        let label = UILabel()
        label.text = "Forgot password?"
        label.font = ApplicationScheme.instance.containerScheme.typographyScheme.subtitle1
        label.textColor = ApplicationScheme.instance.containerScheme.colorScheme.onPrimaryColor
        label.textAlignment = .right
        label.sizeToFit()
        label.isUserInteractionEnabled = true
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(onForgotPasswordClick))
        label.addGestureRecognizer(tapGesture)
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

Does this have something to do with the garbage collector? Unrecognized bounds for the UILabel? Or something else?


Solution

  • The tapGesture in following code is added inside the Closure initializer, and with that you assign target as self which is not valid. Coz self here is not the ViewController

    let forgotPasswordLabel: UILabel = {
            let label = UILabel()
            label.text = "Forgot password?"
            label.font = ApplicationScheme.instance.containerScheme.typographyScheme.subtitle1
            label.textColor = ApplicationScheme.instance.containerScheme.colorScheme.onPrimaryColor
            label.textAlignment = .right
            label.sizeToFit()
            label.isUserInteractionEnabled = true
            let tapGesture = UITapGestureRecognizer(target: self, action: #selector(onForgotPasswordClick))
            label.addGestureRecognizer(tapGesture)
            label.translatesAutoresizingMaskIntoConstraints = false
            return label
        }()
    

    Where as in the following code where the tapGesture is working as expected you are setting target as self which is the ViewController and that is valid.

    let forgotPasswordLabel: UILabel = {
        let label = UILabel()
        label.text = "Forgot password?"
        label.font = ApplicationScheme.instance.containerScheme.typographyScheme.subtitle1
        label.textColor = ApplicationScheme.instance.containerScheme.colorScheme.onPrimaryColor
        label.textAlignment = .right
        label.sizeToFit()
        label.accessibilityRespondsToUserInteraction = true
        label.isUserInteractionEnabled = true
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
    
    let passwordLabel = forgotPasswordLabel
    let tapGesture = UITapGestureRecognizer(target: self, action: #selector(onForgotPasswordClick))
    passwordLabel.addGestureRecognizer(tapGesture)
    self.view.addSubview(passwordLabel)
    

    In case of tapGesture when you set the target it tells that where to look for the action when the gesture happens