Ios 快速计数停止在错误的号码
目标是:统计自用户输入所需天数以来已过去的天数,例如,用户输入3天,计数开始(1、2、3->stop) (我将天改为秒以检查逻辑。) 问题:我尝试了几种方法,但总是遇到相同的问题:计时器在输入天数时停止-1(例如:输入了3,2是屏幕上的最后一个数字,但必须是3!) 我错在哪里 我的代码:Ios 快速计数停止在错误的号码,ios,swift,timer,Ios,Swift,Timer,目标是:统计自用户输入所需天数以来已过去的天数,例如,用户输入3天,计数开始(1、2、3->stop) (我将天改为秒以检查逻辑。) 问题:我尝试了几种方法,但总是遇到相同的问题:计时器在输入天数时停止-1(例如:输入了3,2是屏幕上的最后一个数字,但必须是3!) 我错在哪里 我的代码: import UIKit class ViewController: UIViewController { private let mainLabel = UILabel.makeLabel
import UIKit
class ViewController: UIViewController {
private let mainLabel = UILabel.makeLabel(text: "Day number")
private let startButton = UIButton.makeButton("Start", titleColor: .red, bgColor: .lightGray)
private let stopButton = UIButton.makeButton("Stop", titleColor: .black, bgColor: .lightGray)
private var startDate: Date?
private var endDate: Date?
private let startTimeKey = "StartTime"
private let endTimeKey = "EndDate"
private weak var timer: Timer?
private let defaults = UserDefaults.standard
let dateComponentsFormatter: DateComponentsFormatter = {
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.hour, .minute, .second]
formatter.unitsStyle = .positional
formatter.zeroFormattingBehavior = .pad
return formatter
}()
override func viewDidLoad() {
super.viewDidLoad()
setupLayouts()
endDate = defaults.value(forKey: endTimeKey) as? Date
startDate = defaults.value(forKey: startTimeKey) as? Date
if let endTime = endDate, let startTime = startDate {
if endTime < Date() {
startTimer(endTime: endTime, startTime: startTime)
} else {
timer?.invalidate()
}
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
startButton.addTarget(self, action: #selector(startButtonIsPressed), for: .touchUpInside)
stopButton.addTarget(self, action: #selector(stopButtonIsPressed), for: .touchUpInside)
}
@objc func startButtonIsPressed() {
let alert = UIAlertController(title: "Hello", message: "Enter number of days", preferredStyle: .alert)
let ok = UIAlertAction(title: "OK", style: .default) { [unowned alert] _ in
guard let daysNumber = alert.textFields?.first?.text, !daysNumber.isEmpty else { return }
self.startDate = Date()
self.defaults.set(self.startDate, forKey: self.startTimeKey)
self.endDate = Calendar.current.date(byAdding: .second, value: Int(daysNumber)!, to: Date())
self.defaults.set(self.endDate, forKey: "EndDate")
if self.endDate! > self.startDate! {
self.timer = nil
self.startTimer(endTime: self.endDate!, startTime: self.startDate!)
}
}
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alert.addAction(ok)
alert.addAction(cancel)
alert.addTextField { (textField) in
textField.placeholder = "Number"
textField.keyboardType = .numberPad
}
present(alert, animated: true)
}
@objc func stopButtonIsPressed() {
timer?.invalidate()
}
func startTimer(endTime: Date, startTime: Date) {
defaults.set(endTime, forKey: endTimeKey)
defaults.set(startTime, forKey: startTimeKey)
self.endDate = endTime
self.startDate = startTime
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(handleTimer), userInfo: nil, repeats: true)
}
@objc func handleTimer() {
if endDate! > Date() {
mainLabel.text = dateComponentsFormatter.string(from: startDate!, to: Date())
} else {
timer?.invalidate()
}
}
func setupLayouts() {
view.addSubview(mainLabel)
view.addSubview(startButton)
view.addSubview(stopButton)
NSLayoutConstraint.activate([
mainLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
mainLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor),
startButton.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -70),
startButton.topAnchor.constraint(equalTo: mainLabel.bottomAnchor, constant: 140),
stopButton.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 70),
stopButton.topAnchor.constraint(equalTo: mainLabel.bottomAnchor, constant: 140),
])
}
}
导入UIKit
类ViewController:UIViewController{
private let mainLabel=UILabel.makeLabel(文本:“天数”)
私有let startButton=UIButton.makeButton(“开始”,标题颜色:。红色,背景颜色:。浅灰色)
private let stopButton=UIButton.makeButton(“停止”,标题颜色:。黑色,背景颜色:。浅灰色)
私人var开始日期:日期?
私有变量endDate:日期?
private let startTimeKey=“StartTime”
private let endTimeKey=“EndDate”
专用弱var定时器:定时器?
private let defaults=UserDefaults.standard
让DateComponentFormatter:DateComponentFormatter={
让格式化程序=DateComponentsFormatter()
formatter.allowedUnits=[时、分、秒]
formatter.unitsStyle=.positional
formatter.zeroFormattingBehavior=.pad
返回格式化程序
}()
重写func viewDidLoad(){
super.viewDidLoad()
设置布局()
endDate=默认值。值(forKey:endTimeKey)为?日期
startDate=默认值。值(forKey:startTimeKey)为?日期
如果让endTime=endDate,则让startTime=startDate{
如果endTimeself.startDate{
self.timer=nil
self.startTimer(endTime:self.endDate!,startTime:self.startDate!)
}
}
let cancel=UIAlertAction(标题:“取消”,样式:。取消,处理程序:nil)
alert.addAction(确定)
alert.addAction(取消)
alert.addTextField{(textField)位于
textField.placeholder=“数字”
textField.keyboardType=.numberPad
}
当前(警报、动画:真)
}
@objc func停止按钮按下(){
计时器?.invalidate()
}
func startTimer(结束时间:日期,开始时间:日期){
defaults.set(endTime,forKey:endTimeKey)
set(startTime,forKey:startTimeKey)
self.endDate=endTime
self.startDate=startTime
timer=timer.scheduledTimer(时间间隔:1,目标:self,选择器:#选择器(handleTimer),userInfo:nil,repeats:true)
}
@objc func handleTimer(){
如果endDate!>Date(){
mainlab.text=dateComponentsFormatter.string(从:startDate!到:Date())
}否则{
计时器?.invalidate()
}
}
func setupLayouts(){
view.addSubview(主标签)
view.addSubview(开始按钮)
view.addSubview(停止按钮)
NSLayoutConstraint.activate([
mainLabel.centerXAnchor.constraint(相等于:view.centerXAnchor),
mainLabel.centerYAnchor.constraint(等式:view.centerYAnchor),
startButton.trailingAnchor.constraint(等式:view.safeAreaLayoutGuide.trailingAnchor,常数:-70),
startButton.topAnchor.constraint(等式:mainLabel.bottomAnchor,常量:140),
Stop Button.leadingAnchor.constraint(相等于:view.SafeArea LayoutGuide.leadingAnchor,常数:70),
stopButton.topAnchor.constraint(等式:mainLabel.bottomAnchor,常数:140),
])
}
}
我会将handleTimer()
中的运算符从
更改为=
,我不认为你的代码真的错了,你的测试越多越好。首先计算endDate,然后将其传递给另一个方法并启动计时器,这需要一点时间。然后计时器以1秒的间隔执行,因此当它第三次执行时,很可能endDate以几百分之一秒或更长的时间传递。你需要给它更多的空间。我在操场上进行了一次快速测试,将结束时间设置为+7秒,计时器的间隔设置为2秒,然后handleTimer工作正常