Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/104.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 快速计数停止在错误的号码_Ios_Swift_Timer - Fatal编程技术网

Ios 快速计数停止在错误的号码

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

目标是:统计自用户输入所需天数以来已过去的天数,例如,用户输入3天,计数开始(1、2、3->stop)

(我将天改为秒以检查逻辑。)

问题:我尝试了几种方法,但总是遇到相同的问题:计时器在输入天数时停止-1(例如:输入了3,2是屏幕上的最后一个数字,但必须是3!)

我错在哪里

我的代码:


   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工作正常