2017-07-19 3 views
1

Sorry, wenn dies eine neue Frage ist, bin ich sehr neu in iOS & Swift. Ich habe ein Problem mit dem Timer-Intervall: Ich habe 0.01 Zeitintervall eingestellt, aber es entspricht nicht der Timer-Bezeichnung, weil 0.01 in einer Millisekunde entspricht, aber es zeigt es nicht an. Im Grunde ist der Timer verzerrt.Stoppuhr nicht synchronisiert

timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(updateStopwatch) , userInfo: nil, repeats: true) 

@IBAction func startStopButton(_ sender: Any) { 
    buttonTapped() 
} 


func updateStopwatch() { 
    milliseconds += 1 
    if milliseconds == 100 { 
     seconds += 1 
     milliseconds = 0 
    } 
    if seconds == 60 { 
     minutes += 1 
     seconds = 0 
    } 
    let millisecondsString = milliseconds > 9 ?"\(milliseconds)" : "0\(milliseconds)" 
    let secondsString = seconds > 9 ?"\(seconds)" : "0\(seconds)" 
    let minutesString = minutes > 9 ?"\(minutes)" : "0\(minutes)" 
    stopWatchString = "\(minutesString):\(secondsString).\(millisecondsString)" 
    labelTimer.text = stopWatchString 
} 

func buttonTapped() { 
    if isTimerRunning { 
     isTimerRunning = !isTimerRunning 
     timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(updateStopwatch) , userInfo: nil, repeats: true) 
     startStopButton.setTitle("Stop", for: .normal) 
    }else{ 
     isTimerRunning = !isTimerRunning 
     timer.invalidate() 
     startStopButton.setTitle("Start", for: .normal) 
    } 
} 
+1

.01 es ist nicht 1 Millisekunde –

+2

Sie sollten nie einen Timer verwenden, um Zeit zu berechnen. Speichern Sie einfach das Startdatum und erhalten Sie das Zeitintervall seit diesem Datum. –

+1

Und 100 Millisekunden ist nicht 1 Sekunde. Es ist 0,1 Sekunden. Denken Sie daran, "Milli" ist 1/1000, nicht 1/100. – rmaddy

Antwort

2

Geräte haben eine maximale Bildschirmaktualisierungsrate (die meisten sind 60 fps), daher ist es nicht sinnvoll, schneller zu gehen. Verwenden Sie für die maximale Bildschirmaktualisierungsrate einen CADisplayLink anstelle eines Timer, der perfekt für Bildschirmaktualisierungen (nicht nur in Häufigkeit, sondern auch das Timing innerhalb des Bildschirmaktualisierungszyklus) koordiniert wird.

Versuchen Sie auch nicht, die verstrichene Zeit zu verfolgen, indem Sie einen Wert hinzufügen (weil Sie nicht garantieren können, dass sie mit der gewünschten Frequenz aufgerufen wird). Bevor Sie Ihren Timer/Dispaylink starten, speichern Sie die Startzeit, und wenn der Timer/Dispylink aufgerufen wird, zeigen Sie die verstrichene Zeit im gewünschten Format an.

Zum Beispiel:

var startTime: CFTimeInterval! 
weak var displayLink: CADisplayLink? 

func startDisplayLink() { 
    self.displayLink?.invalidate() // stop prior display link, if any 
    startTime = CACurrentMediaTime() 
    let displayLink = CADisplayLink(target: self, selector: #selector(handleDisplayLink(_:))) 
    displayLink.add(to: .current, forMode: .commonModes) 
    self.displayLink = displayLink 
} 

func handleDisplayLink(_ displayLink: CADisplayLink) { 
    let elapsed = CACurrentMediaTime() - startTime 
    let minutes = Int(elapsed/60) 
    let seconds = elapsed - CFTimeInterval(minutes) * 60 
    let string = String(format: "%02d:%05.2f", minutes, seconds) 

    labelTimer.text = string 
} 

func stopDisplayLink() { 
    displayLink?.invalidate() 
} 

Hinweis, CACurrentMediaTime() verwendet mach_time, wie hotpaw2 richtig vorgeschlagen, aber funktioniert die Umwandlung in Sekunden für Sie.

2

Die Zeitverzögerung eines scheduledTimer ist nur ungefähr, und kann von dem abweichen, was von vielen Millisekunden angefordert wird, aufgrund von iOS-Overhead. Ein sich wiederholender Timer ist für das Timing noch schlechter, da sich jegliche Verzögerungsjitterfehler akkumulieren. Verwenden Sie daher keinen Timer, um längere Ereignisse zu messen.

Ein CADisplayLink ist ein zuverlässigerer Timer, da er mit der Aktualisierung der 60-Hz-Anzeige synchronisiert wird (z. B. ist dies die maximale Rate, mit der UILabel auf anderen Geräten als den neuesten iPad Pros geändert werden kann). Es hat keinen Sinn, eine Zeitanzeige schneller zu aktualisieren (außer möglicherweise bei den neuesten iPad Pros).

Verwenden Sie auch keine Date-Methoden für das Timing, da diese nicht garantiert monoton sind, wenn das Gerät mit einem Netzwerk verbunden ist (da NTP die Uhrzeit mitten in Ihrer Timing-Aktivität ändern kann).

Sie sollten die Benutzeroberfläche für die Messung der verstrichenen Zeit mit einem der integrierten Timer wie mach_time vergleichen. mach_absolute_time() ist garantiert monoton und wird nicht von NTP oder anderen Netzwerkaktivitäten beeinflusst.