【问题标题】:How can I set up timer in Swift?如何在 Swift 中设置计时器?
【发布时间】:2020-11-29 18:41:01
【问题描述】:

我有一个 pickerController 设置小时、分钟和秒,但我不知道如何设置我的计时器,这是我拥有的代码,但它不起作用,我该如何更改?提前致谢

func startTimer() {
    if timer.isValid == true || timeHours == 0  || timeMinutes == 0 || timeSeconds == 0 {
        //do nothing
    } else {
        timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(onTimerFires), userInfo: nil, repeats: true)
    }
}

@objc func onTimerFires() {
    timeHours -= 1
    timeMinuteLabel.text = timeFunc()
    if timeSeconds == 0 {
        timer.invalidate()
    }
}  



func timeFunc() -> String {
    let hours = Int(optionalValuePickerView.selectedRow(inComponent: 0)) 
    let minutes = Int(optionalValuePickerView.selectedRow(inComponent: 1))
    let seconds = Int(optionalValuePickerView.selectedRow(inComponent: 2)) 
    return String(format: "%02i:%02i:%02i", hours, minutes, seconds)
}

【问题讨论】:

  • “不起作用”是出了名的无用。你希望它做什么,而不是做什么?
  • @PhillipMills 在 timeFunc() 函数中,我从 PickerView 中获取值并将其以小时、分钟和秒的形式提供给计时器,问题是当我运行它时,计时器什么也不做,小时,分钟和秒仍然没有改变。那是我的问题,我不知道如何使它成为一个有用的功能计时器

标签: swift timer nstimer


【解决方案1】:

这里有几个问题:

  • 每次调用onTimerFires,它都会递减timeHours(似乎没有在任何地方设置或使用)然后调用timeFunc,它只是从选择器中获取值(在任何地方都没有改变)构建字符串。

  • 这种在定时器中递减计数器的模式做了一个很大的假设,即定时器在正确的时间被准确地调用并且它永远不会错过定时器调用。不幸的是,这不是一个谨慎的假设。

  • 我建议不要使用基于Selector 的计时器,因为这会引入target 的强引用循环。带有weak 引用的基于块的再现更容易避免此类循环。

我会建议一种不同的模式,即您可以节省倒计时的时间:

var countDownDate: Date!

func updateCountDownDate() {
    let components = DateComponents(hour: pickerView.selectedRow(inComponent: 0),
                                    minute: pickerView.selectedRow(inComponent: 1),
                                    second: pickerView.selectedRow(inComponent: 2))

    countDownDate = Calendar.current.date(byAdding: components, to: Date())
}

然后您的计时器处理程序可以计算到目标倒计时日期/时间所经过的时间量:

func handleTimer(_ timer: Timer) {
    let remaining = countDownDate.timeIntervalSince(Date())

    guard remaining >= 0 else {
        timer.invalidate()
        return
    }

    label.text = timeString(from: remaining)
}

当您启动计时器时,您计算countDownDate 并安排计时器:

weak var timer: Timer?

func startTimer() {
    timer?.invalidate() // if one was already running, cancel it

    updateCountDownDate()
    timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] timer in
        guard let self = self else {
            timer.invalidate()
            return
        }

        self.handleTimer(timer)
    }
    timer?.fire()
}

而且,值得一提的是,在准备字符串时,您当然可以确定日期之间的日期组件(即现在和您的目标日期/时间),但您也可以使用 DateComponentsFormatter 为您执行此操作:

let formatter: DateComponentsFormatter = {
    let formatter = DateComponentsFormatter()
    formatter.unitsStyle = .positional
    formatter.allowedUnits = [.hour, .minute, .second]
    formatter.zeroFormattingBehavior = .pad
    return formatter
}()

func timeString(from interval: TimeInterval) -> String? {
    return formatter.string(from: interval)
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-01-02
    • 1970-01-01
    • 2010-10-02
    • 2021-09-22
    • 2011-06-03
    • 1970-01-01
    相关资源
    最近更新 更多