NSTimer太慢了 [英] NSTimer Too Slow

查看:128
本文介绍了NSTimer太慢了的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我见过类似的多个问题;但是,他们都没有解决我的问题。我的计时器太慢了。我只使用 0.01 秒的间隔。这是我的代码:

I have seen multiple questions similar to this; however, none of them resolved my problem. My timer is simply going too slowly. I am only using an interval of 0.01 seconds. Here is my code:

@IBOutlet var timerLabel: UILabel!

var miliseconds = 0
var seconds = 0

func updateLabel() {
    if miliseconds == 0 {
        timerLabel.text = "\(seconds).00"
    } else if miliseconds < 10 {
        timerLabel.text = "\(seconds).0\(miliseconds)"
    } else {
        timerLabel.text = "\(seconds).\(miliseconds)"
    }
}

var timer = NSTimer()

func updateTime() {

    miliseconds++
    if miliseconds == 100 {
        miliseconds = 0
        seconds++
    }
    updateLabel()
}

override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
    if timerState == 1 {
        timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: "updateTime", userInfo: nil, repeats: true)
        NSRunLoop.mainRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)
        timerLabel.textColor = UIColor.blackColor()
        timerState = 2
    }
}

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    if timerState == 0 {
        miliseconds = 0
        seconds = 0
        updateLabel()
        timerLabel.textColor = UIColor.greenColor()
        timerState = 1
    } else if timerState == 2 {
        timerState = 0
        timer.invalidate()
    }
}

var timerState = 0
//timerState of 0 = Has not started
//timerState of 1 = About to start
//timerState of 2 = Timing

我也试过使用延迟:

func delay(delay:Double, closure:()->()) {

    dispatch_after(
    dispatch_time( DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))), dispatch_get_main_queue(), closure)

}

我在 viewDidLoad updateTime $ c>,在 updateTime 结束时,我补充道:

I called updateTime in viewDidLoad, and at the end of updateTime, I added:

delay(0.01) { () -> () in
    self.updateTime()
}

但是,它仍然是和以前一样快。

However, it still went at the same speed as before.

如何解决此问题?如果我在研究过程中遗漏了一个问题,请告诉我。谢谢!

How can I fix this issue? If I missed a question while researching, please let me know. Thanks!

推荐答案

这里有一大堆问题。让我们清理一下。

There is a whole mess of problems here. Let's clean this up.

class ViewController: UIViewController {

    @IBOutlet var timerLabel: UILabel!

首先,不要使用计时器来更新标签。使用 CADisplayLink 。显示链接与屏幕刷新间隔同步,在大多数iOS设备(不是1/100)上是1/60秒,因此您不需要额外的工作:

First of all, don't use a timer to update the label. Use a CADisplayLink. A display link synchronizes with the screen refresh interval, which is 1/60 of a second on most iOS devices (not 1/100), so you don't do extra work:

    private var displayLink: CADisplayLink?

接下来,不要尝试通过在计时器(或链接)处递增计数器来跟踪已用时间)火灾,因为计时器或链接不能保证按您的要求频繁点火。相反,存储计时器启动的时间,以及计时器停止的时间(如果它已停止):

Next, don't try to track the elapsed time by incrementing a counter when the timer (or link) fires, because the timer or link is not guaranteed to fire as often as you requested. Instead, store the time at which the timer was started, and the time at which it was stopped (if it was stopped):

    private var startTime: CFAbsoluteTime = 0
    private var endTime: CFAbsoluteTime = 0 {
        didSet {
            updateLabel()
        }
    }

使用 enum 跟踪状态,而不是神秘的硬编码数字。并且由于标签颜色仅取决于状态,因此将属性添加到为该状态提供标签颜色的状态:

Track the state using an enum instead of mysterious hard-coded numbers. And since the label color depends only the state, add a property to the state that gives the label color for that state:

    private enum State {
        case Stopped
        case Pending
        case Running

        var labelColor: UIColor {
            switch self {
            case .Pending: return UIColor.greenColor()
            case .Stopped, .Running: return UIColor.blackColor()
            }
        }
    }

经过的时间取决于州,所以添加一个计算方法:

The elapsed time depends on the state, so add a method to compute it:

    private var elapsedTime: NSTimeInterval {
        switch state {
        case .Stopped: return endTime - startTime
        case .Running: return CFAbsoluteTimeGetCurrent() - startTime
        case .Pending: return 0
        }
    }

使用格式字符串进行转换向上时字符串的经过时间约会标签:

Use a format string to convert the elapsed time to a string when updating the label:

    private func updateLabel() {
        timerLabel.text = String(format: "%.02f", elapsedTime)
    }

更改计时器状态可以更改标签颜色和已用时间,因此在状态更改时更新标签颜色和标签文本:

Changing the timer state can change both the label color and the elapsed time, so update the label color and the label text when the state changes:

    private var state = State.Stopped {
        didSet {
            timerLabel.textColor = state.labelColor
            updateLabel()
        }
    }

触摸开始时,如果需要,创建显示链接,然后更新状态。州的 didSet 将根据需要处理更新标签:

When a touch begins, create the display link if needed, then update the state. The state's didSet will handle updating the label as necessary:

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        createDisplayLinkIfNeeded()

        switch state {
        case .Stopped:
            state = .Pending
        case .Pending:
            break
        case .Running:
            state = .Stopped
            endTime = CFAbsoluteTimeGetCurrent()
            displayLink?.paused = true
        }
    }

触摸结束时,如有必要,启动计时器:

When a touch ends, start the timer if necessary:

    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        if state == .Pending {
            startTime = CFAbsoluteTimeGetCurrent()
            displayLink?.paused = false
            state = .Running
        }
    }

H. ere是你如何创建显示链接:

Here's how you create the display link:

    private func createDisplayLinkIfNeeded() {
        guard self.displayLink == nil else { return }
        let displayLink = CADisplayLink(target: self, selector: "displayLinkDidFire:")
        displayLink.paused = true
        displayLink.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
        self.displayLink = displayLink
    }

这是显示链接的方法将致电:

And here's the method the display link will call:

    func displayLinkDidFire(_: CADisplayLink) {
        updateLabel()
    }

} // end of ViewController

这篇关于NSTimer太慢了的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆