Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/104.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 同时使用2个计时器_Ios_Multithreading_Swift_Timer_Swift2 - Fatal编程技术网

Ios 同时使用2个计时器

Ios 同时使用2个计时器,ios,multithreading,swift,timer,swift2,Ios,Multithreading,Swift,Timer,Swift2,我需要同时使用两个计时器:一个用于会话,一个用于练习 根据练习的不同,练习可以是计时器或倒计时 我将这个类用于2个计时器,但是我有1s的延迟:我认为这是线程的问题。我试图调度,但没有工作 此外,该类不准确,因为根据可用资源,刷新可能需要比指定的时间更长的时间 你有解决我的问题的办法吗:同时有两个精确的计时器,可以是计时器或倒计时 谢谢你的帮助 public class Chronometer: NSObject { // // MARK: - Private Properties priva

我需要同时使用两个计时器:一个用于会话,一个用于练习

根据练习的不同,练习可以是计时器或倒计时

我将这个类用于2个计时器,但是我有1s的延迟:我认为这是线程的问题。我试图调度,但没有工作

此外,该类不准确,因为根据可用资源,刷新可能需要比指定的时间更长的时间

你有解决我的问题的办法吗:同时有两个精确的计时器,可以是计时器或倒计时

谢谢你的帮助

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