更改 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 你的代码并且它 运行 在我的模拟器上很好),有时它不是。
在这种情况下你有两种选择:
- 将
let
替换为 lazy var
。在这种情况下 self
if always gonna be determined
private lazy var securedButton: UIButton = {
...
}
- 将添加目标移动到您的
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)
}
我创建了一个 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 你的代码并且它 运行 在我的模拟器上很好),有时它不是。
在这种情况下你有两种选择:
- 将
let
替换为lazy var
。在这种情况下self
if always gonna be determined
private lazy var securedButton: UIButton = {
...
}
- 将添加目标移动到您的
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)
}