Проблема с UITextField Timer — проверка «Редактирование изменено», но только один раз для запуска таймера?

#swift #function #delegates #uikit #textfield

#swift #функция #делегаты #uikit #текстовое поле

Вопрос:

Полное раскрытие: я очень новичок во всем, что связано с swift / UIKit, поэтому, надеюсь, вы можете извинить мое уверенное невежество.


Итак, основное действие, которое я пытаюсь выполнить, заключается в том, что таймер немедленно начинает обратный отсчет в тот момент, когда любой символ вводится в a UITextField (НЕ срабатывает только при фокусировке).

Все выглядит и функционирует на 90% так, как я намереваюсь, за исключением взаимодействия, при котором каждый раз, когда символ вводится в текстовое поле, таймер рекурсивно инициирует его timeInterval .

После ввода более 7 символов мой 60-секундный таймер намного превышает 0 менее чем за несколько секунд.

Использование editingDidBegin «исправляет» проблему, но в этом параметре таймер запускается при нажатии и фокусировке текстового поля, а это не идеально для того, что я пытаюсь сделать.

Мой код ViewController:

 import UIKit

class SecondViewController: UIViewController, UITextFieldDelegate {
    var textField: UITextField?
    @IBOutlet weak var countDownLabel: UILabel!   
    var seconds = 60
    var timer = Timer()
    @IBAction func inputTextBar(_ sender: Any) {
        func inputTextBar() {
            self.becomeFirstResponder()
        }
        timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(SecondViewController.counterb), userInfo: nil, repeats: true)
    }
    @objc func counterb() {
        seconds -= 1
        countDownLabel.text = String(seconds)
        if seconds == 0 {
            timer.invalidate()
            countDownLabel.text = "Time's Up!"
        }
    }
    var count = 10
    override func viewDidLoad() {
        super.viewDidLoad()
        textField?.delegate = self
        textField?.becomeFirstResponder()
    }
}
  

Другая отмеченная путаница: если набран только один символ, таймер работает как обычно и печатает «Times Up!» на 0сек. и останавливается.

Но если это связано с ускорением, о котором я упоминал, после ввода нескольких символов таймер пролетает мимо 0 и никогда не становится недействительным.

Я предполагаю, что это проблема с обновлением.

Редактировать:

Хорошо, я понял, что, создавая переменную weak timer, я смог заставить таймер не продолжать укладку на себя. Но с переменной weak таймер вообще не запускается, пока UITextField вводится!

Полуфиксированный код:

 weak var timer: Timer?
@IBAction func inputTextBar(_ sender: AnyObject) {
    timer?.invalidate()      
    timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(SecondViewController.loop), userInfo: nil, repeats: true)
}    
@objc func loop() {
    seconds -= 1
    countDownLabel.text = String(seconds)   
    if self.seconds == 0 {
        timer?.invalidate()
        countDownLabel.text = "Time's Up!"
    }   
}
  

Комментарии:

1. Редактировать: Хорошо, я понял, что, создавая переменную weak timer, я смог заставить таймер не продолжать укладку на себя. Но с переменной weak таймер вообще не запускается, пока UITextField вводится!

Ответ №1:

Сначала измените объявление таймера на необязательное. Затем вы можете просто проверить, равно ли оно нулю, если true запланируйте свой таймер. Во-вторых, вы никогда не должны полагаться на таймер для измерения прошедшего времени. Просто создайте конечную дату, добавив желаемый интервал времени с этого момента. Таким образом, вы можете просто проверить, больше или равно ли значение now конечной дате при аннулировании вашего таймера. Используйте таймер только для обновления пользовательского интерфейса, и вы можете просто проверить интервал времени с этого момента при обновлении вашей метки. Приведенный ниже код был написан в браузере, поэтому в нем могут быть некоторые ошибки, но вы можете иметь представление о том, что делать для достижения вашей цели.

 class SecondViewController: UIViewController {
    @IBOutlet weak var textField: UITextField!
    @IBOutlet weak var countDownLabel: UILabel!
    var endDate: Date? = nil
    var timer: Timer? = nil
    override func viewDidLoad() {
        super.viewDidLoad()
        textField.addTarget(self, action: #selector(editingChanged), for: .editingChanged)
        textField.becomeFirstResponder()
    }
    @objc func editingChanged(_ textField: UITextField) {
        if timer == nil {
            timer = .scheduledTimer(timeInterval: 1,
                                    target: self,
                                    selector: #selector(counterb),
                                    userInfo: nil,
                                    repeats: true)
            endDate = Date().addingTimeInterval(60)
        }
    }
    @objc func counterb() {
        countDownLabel.text = String(format: "%.0f", endDate!.timeIntervalSinceNow.rounded(.up))
        if Date() >= endDate! {
            timer?.invalidate()
            timer = nil
            endDate = nil
            countDownLabel.text = "Time's Up!"
        }
    }
}
  

Комментарии:

1. БИНГО! Это сделало все, что я пытался выполнить после того, как я связал все вместе! Спасибо за объяснение этого. тогда «timeIntervalSinceNow» должен мне очень помочь. Уже 2 дня ищу кого-то с такой же проблемой.