#ios #swift #uitextfield
Вопрос:
Я создал подкласс 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 в редактируемом текстовом поле. Как это исправить?
Комментарии:
1.
tag
концепция использования
Ответ №1:
Когда вы создаете свою let
переменную с блоком самостоятельного вызова, вы не должны ее использовать self
, так как в данный момент она не определена. Вы можете добавить печать, чтобы увидеть ее значение, это не ваше представление, потому что представление еще не создано.
Иногда это будет правильное значение в конце(я попытался запустить ваш код, и он отлично работает на моем симуляторе), а иногда это не так.
В таких случаях у вас есть два варианта:
- Заменить
let
наlazy var
. В этом случаеself
, если всегда будет определяться
private lazy var securedButton: UIButton = {
...
}
- Переместите добавление цели в свой
init
. Если вы используете много входов, не забудьте добавить их все, предпочтительно перейдя к другой функции. Я предпочитаю этот способ, чтобы убедиться, что все мои реквизиты есть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)
}
Комментарии:
1. Означает ли это, что более безопасно использовать lazy var во всех свойствах UIView?
2. @belkavkolese это нужно только тогда, когда вам нужно было
self
добавить цель/делегата/что угодно. На самом деле вы можете уйтиlet
, но переместиться, добавив целевой код в свойinit
тоже3. @belkavkolese Я добавил второй способ исправить это(с помощью инициализации) в свой ответ, я на самом деле нахожу его предпочтительным в целом