Изменение isSecureTextEntry используется в неправильном текстовом поле

#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 , так как в данный момент она не определена. Вы можете добавить печать, чтобы увидеть ее значение, это не ваше представление, потому что представление еще не создано.

Иногда это будет правильное значение в конце(я попытался запустить ваш код, и он отлично работает на моем симуляторе), а иногда это не так.

В таких случаях у вас есть два варианта:

  1. Заменить let на lazy var . В этом случае self , если всегда будет определяться
 private lazy var securedButton: UIButton = {
   ...
}

 
  1. Переместите добавление цели в свой 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 Я добавил второй способ исправить это(с помощью инициализации) в свой ответ, я на самом деле нахожу его предпочтительным в целом