#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 дня ищу кого-то с такой же проблемой.