Button to instanciate ViewController is not working after hiding it

折月煮酒 提交于 2020-12-06 06:51:05

问题


I have this very weird problem that I just found out...

I have this button which is triggering this function:

@objc func vergessenTapped() {
    let forgotPasswordVC = self.storyboard?.instantiateViewController(withIdentifier: "ForgotPasswordVC") as! ForgotPasswordVC
    forgotPasswordVC.email = self.emailTextField.text!
    self.present(forgotPasswordVC, animated: true, completion: nil)
}

I also have these function which hide/show the button above:

    // delegate Methode für eye-Button
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
    switch textField {
    case passwordTextField:
        if passwordTextField.text != "" {
            eyeButton.isHidden = false
            vergessenButton.isHidden = true
        } else {
            eyeButton.isHidden = true
        }

        break
    default:
        break
    }
    return true
}
// delegate Methode für eye-Button
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
    
    if textField == passwordTextField {
        self.eyeButton.isHidden = true
        self.vergessenButton.isHidden = false
    }
    return true
}

@objc func textFieldDidChange(_ textField: UITextField) {
    if textField.text == "" {
        self.eyeButton.isHidden = true
        self.vergessenButton.isHidden = false
    }else {
        self.vergessenButton.isHidden = true
        self.eyeButton.isHidden = false
    }
}

Now the Problem:

When I press the button the first time before any of the delegate-function above are hiding it, the ViewController it presents works just fine.

However: As soon as the button is hidden for the first time, and the user clicks it after it is visible again the forgotpasswordViewController behaves really really weird, e.g:

1. when calling self.dismiss , the `ViewController is actually not dismissed, but is popping the one below it.

@objc func backButtonTapped(){
    self.dismiss(animated: true, completion: nil)
}

2. The button in the forgotpasswordViewController (only one button there) is not doing anything.

Here is a Screenvideo for a better understanding. 22 seconds into the video I start typing (somehow not visible on the screenvideo but you can see that the "vergessen" but disappears and appears again. After appearing again I click it and as you can see, neither the backButton nor the confirmButton work like they did before...

Is this some kind of bug??? I can't explain it .. so if anyone helps me out here I would really appreciated!

Demo-Project:

Demo-Project


回答1:


It has nothing to do with showing and hiding the Vergessen button. The problem is this sort of thing in your ForgotPassword view controller (and your other view controller too, actually):

let backButton: UIButton = {
    let v = UIButton()
    v.translatesAutoresizingMaskIntoConstraints = false
    v.setImage(UIImage(named:"down"), for: .normal)
    v.addTarget(self, action: #selector(backButtonTapped), for: .touchUpInside)
    return v
}()

There is something very wrong with that. Do you see what it is? Of course not, because this is one of the nastiest little traps in all of iOS programming. You cannot say v.addTarget(self... in the initializer of an instance property. Why? Because the instance self (here, the view controller) is what we are in the middle of initializing. So self has no meaning here. Well, sometimes it has a meaning and sometimes it doesn't; the real trap for you is that the code ever worked. That really misled you. (Also you were misled by the fact that the code compiled. In my opinion, it should not. I have a filed a bug, if it's any comfort.)

Okay, so I can think of a lot of solutions, but traditionally what we do here is replace let with lazy var. I think I see six places in your code where you need to do that.

lazy var backButton: UIButton = { // ... and so on

And when you do, everything will start working just fine.

The reason this fixes the problem is that lazy postpones the running of that code until after the view controller itself has been initialized. So then self means what it is supposed to mean.

(I'm sorry there is no lazy let, but there's nothing I can do about that. You just have to say lazy var and let it go at that.)

I should also add that, new in iOS 14, you can (if you wish) stop calling addTarget(_:action:for:), and that way you won't fall into this trap ever again. But the fix, which is to add a UIAction to the button, is only on iOS 14 and later.



来源:https://stackoverflow.com/questions/63892806/button-to-instanciate-viewcontroller-is-not-working-after-hiding-it

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!