在 Swift 中将 for 循环与计时器同步
Synchronizing a for loop with timers in Swift
我正在处理的部分应用程序涉及存储在对象数组中的一系列计时器。理想情况下,我想遍历这个数组,获取计时器的持续时间并继续倒计时。计时器结束后,转到数组中的下一项并重复该过程
for(index, content) in enumerate timerList{
doneTimer = NSTimer.scheduledTimerWithTimeInterval(timerList[index].duration, target: self, selector: Selector("finished:"), userInfo: nil, repeats: false)
}
func finished(timer : NSTimer){
//do whatever and tell the loop to get the next item?
}
放置这个 for 循环 "on hold" 直到计时器结束再转到数组中的下一项的最佳方法是什么?
在任何类型的 GUI 应用程序中,基本规则之一是您永远不想 "pause" 或 "stop" 或 "wait." 相反,您想要做的是开始一个操作稍后将完成,返回 GUI,然后当该操作完成时,从您停止的地方继续。
在您问题的上下文中,您尝试做的似乎是找到最近的计时器,启动它,在 GUI 中显示一些内容,然后在计时器触发之前不执行任何操作。
考虑到这一点,您要采用的基本模型是找到最早的计时器,启动它,在 GUI 中显示一些内容,然后返回系统。当该计时器触发时,您可以重复该过程。
你原来的问题有很多含糊不清的地方,你最终会得到这样的结果:
class TimerController {
var timers = [Timer]()
var runningTimer : NSTimer?
var countDownDisplay : UILabel?
class Timer {
let fireDate : NSDate
init(fireDate:NSDate) {
self.fireDate = fireDate
}
}
// given an array of NSTimer, find the earliest one to fire
func findEarliestTimer() -> Timer? {
return timers.sorted( { return [=10=].fireDate.timeIntervalSince1970 < .fireDate.timeIntervalSince1970 } ).first
}
func scheduleEarliestTimer() {
runningTimer?.invalidate()
runningTimer = nil
if let timer = findEarliestTimer() {
let duration = min(1.0, timer.fireDate.timeIntervalSinceNow)
runningTimer = NSTimer.scheduledTimerWithTimeInterval(duration, target: self, selector: "finish", userInfo: timer, repeats: false)
}
}
func finish(nstimer:NSTimer) {
let timer = nstimer.userInfo as Timer
// update the gui countdown
self.countDownDisplay?.text = "\(floor(timer.fireDate.timeIntervalSinceNow))"
// remove timer
timers = timers.filter { [=10=] !== timer }
// schedule the next timer
self.scheduleEarliestTimer()
}
}
请注意,我使用 NSDate 来保持计时器关闭而不是持续时间,因为 "duration" 仅在已知起点时才有意义。如果想连续触发一串固定时长的操作,酌情修改。
由于您想要显示某种倒计时,您需要修改 NSTimer 以每秒触发一次直到适当的时间,每次触发更新倒计时。
我正在处理的部分应用程序涉及存储在对象数组中的一系列计时器。理想情况下,我想遍历这个数组,获取计时器的持续时间并继续倒计时。计时器结束后,转到数组中的下一项并重复该过程
for(index, content) in enumerate timerList{
doneTimer = NSTimer.scheduledTimerWithTimeInterval(timerList[index].duration, target: self, selector: Selector("finished:"), userInfo: nil, repeats: false)
}
func finished(timer : NSTimer){
//do whatever and tell the loop to get the next item?
}
放置这个 for 循环 "on hold" 直到计时器结束再转到数组中的下一项的最佳方法是什么?
在任何类型的 GUI 应用程序中,基本规则之一是您永远不想 "pause" 或 "stop" 或 "wait." 相反,您想要做的是开始一个操作稍后将完成,返回 GUI,然后当该操作完成时,从您停止的地方继续。
在您问题的上下文中,您尝试做的似乎是找到最近的计时器,启动它,在 GUI 中显示一些内容,然后在计时器触发之前不执行任何操作。
考虑到这一点,您要采用的基本模型是找到最早的计时器,启动它,在 GUI 中显示一些内容,然后返回系统。当该计时器触发时,您可以重复该过程。
你原来的问题有很多含糊不清的地方,你最终会得到这样的结果:
class TimerController {
var timers = [Timer]()
var runningTimer : NSTimer?
var countDownDisplay : UILabel?
class Timer {
let fireDate : NSDate
init(fireDate:NSDate) {
self.fireDate = fireDate
}
}
// given an array of NSTimer, find the earliest one to fire
func findEarliestTimer() -> Timer? {
return timers.sorted( { return [=10=].fireDate.timeIntervalSince1970 < .fireDate.timeIntervalSince1970 } ).first
}
func scheduleEarliestTimer() {
runningTimer?.invalidate()
runningTimer = nil
if let timer = findEarliestTimer() {
let duration = min(1.0, timer.fireDate.timeIntervalSinceNow)
runningTimer = NSTimer.scheduledTimerWithTimeInterval(duration, target: self, selector: "finish", userInfo: timer, repeats: false)
}
}
func finish(nstimer:NSTimer) {
let timer = nstimer.userInfo as Timer
// update the gui countdown
self.countDownDisplay?.text = "\(floor(timer.fireDate.timeIntervalSinceNow))"
// remove timer
timers = timers.filter { [=10=] !== timer }
// schedule the next timer
self.scheduleEarliestTimer()
}
}
请注意,我使用 NSDate 来保持计时器关闭而不是持续时间,因为 "duration" 仅在已知起点时才有意义。如果想连续触发一串固定时长的操作,酌情修改。
由于您想要显示某种倒计时,您需要修改 NSTimer 以每秒触发一次直到适当的时间,每次触发更新倒计时。