我需要同时使用2个计时器:一个用于会话,一个用于练习。
根据练习,练习者可以是计时器或倒计时。
我将这个课程用于2个计时器,但我有1秒的延迟:我认为这是一个线程问题。我试图派遣但不工作。
此外,该类不准确,因为根据可用资源,刷新可能需要比指定时间更长的时间。
你有解决方案来解决我的问题:有2个准确的计时器,可以是计时器还是倒计时?
感谢您的帮助
public class Chronometer: NSObject {
//
// MARK: - Private Properties
private var startTime = NSTimeInterval(0)
private var accumulatedTime = NSTimeInterval(0)
private var elapsedSinceLastRefresh = NSTimeInterval(0)
private var timer = NSTimer()
//
// MARK: - Public Properties
public var elapsedTime: NSTimeInterval {
return elapsedSinceLastRefresh + accumulatedTime
}
/// The Time Interval to refresh the chronometer. The default is 1 second
public var refreshInterval = NSTimeInterval(1)
/// Determines a time limit for this Chronometer
public var timeLimit: NSTimeInterval?
/// Optional Block that gets called on each refresh of the specified time interval.
/// If this class needs to update UI, make sure that the UI class are made in the
/// main thread, or dispatched into it.
public var updateBlock: ((NSTimeInterval, NSTimeInterval?) -> ())?
/// Optional Block that gets called when the chronometer reach its limit time
public var completedBlock: (() -> ())?
//
// MARK: - Initializers
///
/// A convenience initializer that allow specifying the refresh interval
/// :param: refreshInterval The desired refresh interval
///
public convenience init(refreshInterval: NSTimeInterval) {
self.init()
self.refreshInterval = refreshInterval
}
///
/// A convenience initializer that allow specifying the refesh interval and update block
/// :param: refreshInterval The desired refresh interval
/// :param: updateBlock The update block to be called on each refresh
///
public convenience init(refreshInterval: NSTimeInterval, updateBlock: (NSTimeInterval, NSTimeInterval?) -> ()) {
self.init()
self.refreshInterval = refreshInterval
self.updateBlock = updateBlock
}
//
// MARK: - Internal Methods
///
/// Refresh the timer, calling the update block to notify the tracker about the new value.
///
func refreshTime() {
// Calculate the new time
var refreshTime = NSDate.timeIntervalSinceReferenceDate()
self.elapsedSinceLastRefresh = (refreshTime - startTime)
// Calculates the remaining time if applicable
var remainingTime: NSTimeInterval? = nil
if self.timeLimit != nil {
remainingTime = self.timeLimit! - elapsedTime
}
// If an update block is specified, then call it
self.updateBlock?(elapsedTime, remainingTime)
// If the chronometer is complete, then call the block and
if let limit = self.timeLimit {
if self.elapsedTime >= limit {
self.stop()
self.completedBlock?()
}
}
}
//
// MARK: - Public Methods
///
/// Set a time limit for this chronometer
///
public func setLimit(timeLimit: NSTimeInterval, withCompletionBlock completedBlock: () -> ()) {
self.timeLimit = timeLimit
self.completedBlock = completedBlock
}
///
/// Start the execution of the Cronometer.
/// Start will take place using accumulated time from the last session.
/// If the Cronometer is running the call will be ignored.
///
public func start() {
if !timer.valid {
// Create a new timer
timer = NSTimer.scheduledTimerWithTimeInterval(self.refreshInterval,
target: self,
selector: "refreshTime",
userInfo: nil,
repeats: true)
// Set the base date
startTime = NSDate.timeIntervalSinceReferenceDate()
}
}
///
/// Stops the execution of the Cronometer.
/// Keeps the accumulated value, in order to allow pausing of the chronometer, and
/// to keep "elapsedTime" property value available for the user to keep track.
///
public func stop() {
timer.invalidate()
accumulatedTime = elapsedTime
elapsedSinceLastRefresh = 0
}
///
/// Resets the Cronometer.
/// This method will stop chronometer if it's running. This is necessary since
/// the class is not thread safe.
///
public func reset() {
timer.invalidate()
elapsedSinceLastRefresh = 0
accumulatedTime = 0
}
}
在我的UIViewController中,在viewDidLoad()中:
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)) { [unowned self] in
self.chronometerWorkout = Chronometer(refreshInterval: NSTimeInterval(0.01)) {
(elapsedTime: NSTimeInterval, remainingTime: NSTimeInterval?) in
dispatch_async(dispatch_get_main_queue()) {
if let r = remainingTime {
self.counterView?.chronoWorkoutLabel.text = r.getFormattedInterval(miliseconds: false)
} else {
self.secondsChronoWorkout = elapsedTime
self.counterView?.chronoWorkoutLabel.text = elapsedTime.getFormattedInterval(miliseconds: false)
}
}
}
}
self.chronometerExo = Chronometer(refreshInterval: NSTimeInterval(0.01)) {
(elapsedTime: NSTimeInterval, remainingTime: NSTimeInterval?) in
if let r = remainingTime {
self.counterView?.chronoExoLabel.text = r.getFormattedInterval(miliseconds: false)
self.graphicView.yValues[self.selectedRow] = Double(remainingTime!)
self.counterView?.circularTimerProgressView.progress = CGFloat(remainingTime!)
} else {
self.secondsChronoExo = elapsedTime
self.counterView?.chronoExoLabel.text = elapsedTime.getFormattedInterval(miliseconds: false)
self.graphicView.yValues[self.selectedRow] = Double(elapsedTime)
self.counterView?.circularTimerProgressView.progress = CGFloat(elapsedTime)
}
}
更新:
var startWorkOutDate:CFAbsoluteTime!
var startExoTime:CFAbsoluteTime!
var timeReference:Double!
func updateTimerLabels() {
let elapsedTimeWorkOut = CFAbsoluteTimeGetCurrent() - startWorkOutDate
self.counterView?.chronoWorkoutLabel.text = String(format: "%.2f",elapsedTimeWorkOut)
let startExoTime = self.startExoTime ?? 0.0
let elapsedTimeExo = CFAbsoluteTimeGetCurrent() - startExoTime
if timeReference != 0 {
if elapsedTimeExo <= timeReference {
let remainingTimeExo = timeReference - elapsedTimeExo
self.counterView?.chronoExoLabel.text = String(format: "%.2f",remainingTimeExo)
}
}
}
func startTimers(indexPath: NSIndexPath){
...
if self.startWorkoutChronometer == false {
startWorkOutDate = CFAbsoluteTimeGetCurrent()
self.startWorkoutChronometer = true
self.startExoChronometer = true
_ = NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: Selector("updateTimerLabels"), userInfo: nil, repeats: true)
}
if self.startExoChronometer == true {
if timeReference != 0 {
if self.graphicView.yValues[selectedRow] == timeReference {
startExoTime = CFAbsoluteTimeGetCurrent()
} else {
timeReference = Double(Int(self.graphicView.yValues[selectedRow]))
}
}
}
}
答案 0 :(得分:0)
考虑每个计时器不使用1 NSTimer
个实例。使用NSTimer
或甚至可能显示链接'仅触发对UI的更新。
对于您的计时器,只需将开始时间记录为NSDate
和计时器类型。提供一种询问当前时间或显示值的方法。然后,计时器可以根据当前设备时间在运行中计算出来。
通过这种方式,您将无法滑动或偏移,您可以根据需要更新UI。