Ios 同时使用2个计时器
我需要同时使用两个计时器:一个用于会话,一个用于练习 根据练习的不同,练习可以是计时器或倒计时 我将这个类用于2个计时器,但是我有1s的延迟:我认为这是线程的问题。我试图调度,但没有工作 此外,该类不准确,因为根据可用资源,刷新可能需要比指定的时间更长的时间 你有解决我的问题的办法吗:同时有两个精确的计时器,可以是计时器或倒计时 谢谢你的帮助Ios 同时使用2个计时器,ios,multithreading,swift,timer,swift2,Ios,Multithreading,Swift,Timer,Swift2,我需要同时使用两个计时器:一个用于会话,一个用于练习 根据练习的不同,练习可以是计时器或倒计时 我将这个类用于2个计时器,但是我有1s的延迟:我认为这是线程的问题。我试图调度,但没有工作 此外,该类不准确,因为根据可用资源,刷新可能需要比指定的时间更长的时间 你有解决我的问题的办法吗:同时有两个精确的计时器,可以是计时器或倒计时 谢谢你的帮助 public class Chronometer: NSObject { // // MARK: - Private Properties priva
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
}
}
在my 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)
}
}
更新:
考虑每个计时器不使用1个NSTimer实例。使用NSTimer,甚至可能仅显示链接来触发对UI的更新
对于计时器,只需将开始时间记录为NSDate和计时器类型。提供询问当前时间或显示值的方法。然后,计时器可以根据当前设备时间动态计算
通过这种方式,您将不会出现滑动或偏移,并且可以随心所欲地快速更新UI。当其中一个计时器处于倒计时模式时,我仍有一秒的延迟。我已经用新代码更新了我的第一篇文章。我的pb在哪里?我认为转换成字符串的延迟在哪里?您应该存储对计时器的引用,以便停止它。何时调用startTimers?从UITableView选定的行调用startTimers。timeReference是从带有行索引的时间数组中获取的。在训练计时器和exo计时器之间的开始处观察到延迟,即训练的时间为00:02,exo时间参考=20的时间为00:17。对计时器的引用可以存储在用户信息中,就是这样吗?计时器应该存储在视图控制器中。理想情况下,您可以将计时器与此逻辑分离,最初您可以让它在VC在屏幕上的整个时间内运行。我真的不明白你对时间参考的用法。我会为每个“计时器”设置一个对象,并在每个“计时器”中存储开始日期和持续时间。目前我得到的印象是,您没有很好地将模型、视图和控制器之间的逻辑和数据分离开来,这会导致混乱和复杂性……如果我理解的话,最好在viewDidLoad或ViewWillAspect中设置计时器,调用updateLabels方法?我有一个uitableview,每行uitableview有不同的练习和不同的时间。因此,当我选择一行时,我想启动训练计时器和一个获得锻炼时间参考的锻炼。每次我选择一行时,必须重新初始化并重新启动exercice的计时器。我不明白:每个“计时器”都有一个对象,并在每个“计时器”中存储开始日期和持续时间。更清楚了吗?
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]))
}
}
}
}