UITextField + 计时器问题 - 检查 "Editing Changed" 但只有一次启动计时器?
UITextField + Timer Issue - Checking for "Editing Changed" but Only Once to Initiate Timer?
完全披露: 我对一切都非常陌生swift/UIKit-related所以我希望你能原谅我的无知。
所以我要执行的基本操作是让计时器在任何字符输入 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()
}
}
其他值得注意的混淆: 如果只键入一个字符,计时器将正常进行并在 0 秒时打印 "Times Up!" .并停止。
但是如果它在我提到的速度堆积上,在输入几个字符后,计时器飞过 0 并且永远不会失效。
我认为这是一个刷新问题。
编辑:
好吧,我想通了使定时器变量 weak
我能够让定时器不继续堆叠自己。但是,对于 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!"
}
}
首先将您的计时器声明更改为可选。然后你可以简单地检查它是否为零,如果为真则安排你的计时器。其次,您永远不应该依赖计时器来测量经过的时间。只需创建一个结束日期,添加从现在开始所需的时间间隔。这样您就可以在使计时器无效时简单地检查 now 是否大于或等于 endDate 。仅使用计时器来更新 UI 并且您可以在更新标签时简单地检查从现在开始的时间间隔。以下代码是在浏览器中编写的,因此可能存在一些错误,但您可以知道如何实现您的目标。
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!"
}
}
}
完全披露: 我对一切都非常陌生swift/UIKit-related所以我希望你能原谅我的无知。
所以我要执行的基本操作是让计时器在任何字符输入 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()
}
}
其他值得注意的混淆: 如果只键入一个字符,计时器将正常进行并在 0 秒时打印 "Times Up!" .并停止。
但是如果它在我提到的速度堆积上,在输入几个字符后,计时器飞过 0 并且永远不会失效。
我认为这是一个刷新问题。
编辑:
好吧,我想通了使定时器变量 weak
我能够让定时器不继续堆叠自己。但是,对于 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!"
}
}
首先将您的计时器声明更改为可选。然后你可以简单地检查它是否为零,如果为真则安排你的计时器。其次,您永远不应该依赖计时器来测量经过的时间。只需创建一个结束日期,添加从现在开始所需的时间间隔。这样您就可以在使计时器无效时简单地检查 now 是否大于或等于 endDate 。仅使用计时器来更新 UI 并且您可以在更新标签时简单地检查从现在开始的时间间隔。以下代码是在浏览器中编写的,因此可能存在一些错误,但您可以知道如何实现您的目标。
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!"
}
}
}