2016-02-19 2 views
-2

Я видел несколько вопросов, подобных этому; однако ни одна из них не разрешила мою проблему. Мой таймер просто идет слишком медленно. Я использую только интервал 0.01 секунд. Вот мой код:NSTimer Too Slow

@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) 

} 

Я назвал updateTime в viewDidLoad, и в конце updateTime, я добавил:

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

Однако , он по-прежнему шел с той же скоростью, что и раньше.

Как исправить эту проблему? Если я пропустил вопрос во время исследования, пожалуйста, дайте мне знать. Благодаря!

+0

Можете ли вы объяснить, что проблема, которую вы пытаетесь решить? – UlyssesR

+0

ли достаточно 0,01 с выполнения этой задачи вы запросили в каждом цикле? Если нет, то выполнение интервала будет задержана/пропущено. Кроме того,' NSTimer' имеет низкое разрешение. Прочитайте [this] (http://stackoverflow.com/a/18584973/188331) – Raptor

+0

@UlyssesR, мой таймер идет слишком медленно. Как это исправить? – penatheboss

ответ

7

Здесь есть целый беспорядок. Давайте очистим это.

class ViewController: UIViewController { 

    @IBOutlet var timerLabel: UILabel! 

Прежде всего, не используйте таймер для обновления этикетки. Используйте CADisplayLink. Ссылка индикации синхронизируется с интервалом обновления экрана, что 1/60 секунды на большинстве IOS устройств (не 1/100), так что вы не делаете дополнительную работу:

private var displayLink: CADisplayLink? 

Далее, не попробуйте отслеживать прошедшее время, увеличивая счетчик, когда срабатывает таймер (или ссылка), так как таймер или ссылка не гарантируется, чтобы срабатывать так часто, как вы просили. Вместо этого, сохранить время, на котором был запущен таймер, и время, в котором он был остановлен (если он был остановлен):

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

Отслеживание состояния с помощью enum вместо загадочных жестко закодированных чисел. А так как цвет этикетки зависит только от состояния, добавить свойство в состоянии, которое дает цвет метки для этого состояния:

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() 
      } 
     } 
    } 

зависит от состояния истекшего времени, поэтому добавьте метод, чтобы вычислить его:

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

Используйте строку формата для преобразования времени, истекшего в строку при обновлении метки:

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

Изменения состояния таймера можно изменить как цвет этикетки и истекшее время, так обновить цвет этикетки и текст метки при изменении состояния:

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

Когда начинается прикосновение, создать ссылку дисплея, если это необходимо, а затем обновить состояние.Государства didSet будут обрабатывать обновления этикетки по мере необходимости:

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 
     } 
    } 

Когда прикосновение заканчивается, запуск таймера, если необходимо:

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

Вот как создать ссылку дисплея:

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 
    } 

И вот метод, по которому будет отображаться ссылка:

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

} // end of ViewController 
+0

Я просмотрел ответ ... Похоже, он решит мою проблему. Я попробую, когда у меня появится шанс. Спасибо за ответ! – penatheboss

+0

Итак, я попробовал код, и почти все работает gre в. Однако, когда я останавливаю таймер, я получаю странное отрицательное число в качестве моего конечного времени ... Что может быть причиной этого? – penatheboss

+0

Я забыл обновить ярлык после установки 'endTime'. Я добавил наблюдателя 'didSet' в' endTime', чтобы исправить эту проблему. –

0

Из моего комментария выше ... (с воодушевлением)

NSTimer - от яблочных документации для разработчиков:

«Таймер не является механизмом реального времени; он срабатывает только тогда, когда работает один из режимов цикла петли , к которому был добавлен таймер, и может проверить, прошло ли время срабатывания таймера. Из-за различных источников входного сигнала выполняется типичный цикл запуска, эффективное разрешение . Временной интервал для таймера ограничен величиной 50-100 миллисекунд. "