更改 isSecureTextEntry 用于错误的文本字段

Changing isSecureTextEntry is being used on a wrong textField

我创建了一个 UIView 的子类,其中包含一个文本字段和一个按钮,如果文本字段通过 isSecureTextEntry 属性 受到保护,则允许配置该按钮。 我正在使用该视图的两个实例,一个用于设置密码,另一个用于在这样的视图控制器中确认它

let passwordTextField = PasswordTextFieldView(placeholder: "New password")
let confirmPasswordTextField = PasswordTextFieldView(placeholder: "Confirm password")

文本字段子类代码

final class PasswordTextFieldView: UIView {
    lazy var textField: UITextField = {
        let textField = UITextField()
        textField.textColor = .black
        textField.placeholder = placeholder
        textField.textAlignment = .left
        textField.textContentType = .password
        textField.autocorrectionType = .no
        textField.isSecureTextEntry = true
        return textField
    }()
    
    private let securedButton: UIButton = {
        let button = UIButton(type: .system)
        button.setImage(UIImage(systemName: "eye.slash.fill")?.withRenderingMode(.alwaysTemplate), for: .normal)
        button.tintColor = .gray
        button.addTarget(self, action: #selector(securedButtonTapped), for: .touchUpInside)
        return button
    }()
    
    private var isSecured: Bool = true
    
    var placeholder: String
    
    required init(placeholder: String) {
        self.placeholder = placeholder
        super.init(frame: CGRect.zero)
        // Layout views
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    @objc func securedButtonTapped() {
        isSecured.toggle()
        securedButton.setImage(UIImage(systemName: isSecured ? "eye.slash.fill" : "eye.fill"), for: .normal)
        textField.isSecureTextEntry = isSecured
    }
}

所以问题是,点击按钮会更改正在编辑的文本字段上的 isSecureTextEntry。如何解决?

当您使用自调用块创建 let 变量时,您不应使用 self,因为此时尚未确定。您可以添加打印以查看它的值,这不是您的视图,因为尚未创建视图。

有时它最后会是正确的值(我试过 运行ning 你的代码并且它 运行 在我的模拟器上很好),有时它不是。

在这种情况下你有两种选择:

  1. let 替换为 lazy var。在这种情况下 self if always gonna be determined
private lazy var securedButton: UIButton = {
   ...
}

  1. 将添加目标移动到您的init。如果您正在使用许多 inits,请不要忘记添加到所有 inits,最好移动到其他函数。如果我不需要更改它,我更喜欢这种方式来确保我所有的道具都是 let。像这样:
required init(placeholder: String) {
    self.placeholder = placeholder
    super.init(frame: CGRect.zero)
    initialize()
}

required init?(coder: NSCoder) {
    super.init(coder: coder)
    initialize()
    // I know you're not using this initializer, just in case you'd need in future
}

private func initialize() {
    securedButton.addTarget(self, action: #selector(securedButtonTapped), for: .touchUpInside)
}