如何在Swift中暂停和恢复NSTimer.scheduledTimerWithTimeInterval?

33

我正在开发一款游戏,希望创建一个暂停菜单。这是我的代码:

self.view?.paused = true

但是NSTimer.scheduledTimerWithTimeInterval仍在运行...

 for var i=0; i < rocketCount; i++ {
    var a: NSTimeInterval = 1
    ii += a
    delaysShow = 2.0 + ((stimulus + interStimulus) * ii)       
    var time3 = NSTimer.scheduledTimerWithTimeInterval(delaysShow!, target: self, selector: Selector("showRocket:"), userInfo: rocketid[i], repeats: false)
 }

我希望当玩家点击暂停菜单时,time3 可以暂停计时器,并且当玩家回到游戏时继续运行计时器,但是我该如何暂停 NSTimer.scheduledTimerWithTimeInterval?请帮助我。


1
只是想澄清一下,当按下“暂停”按钮时,您想要暂停现有的计时器...当按下“恢复”按钮时,您想要恢复计时器...是这样吗? - Karthik
9个回答

54
您需要将其无效化并重新创建。然后,如果您有相同的按钮来暂停和恢复计时器,则可以使用isPaused布尔值来跟踪状态:
var isPaused = true
var timer = NSTimer()    
@IBAction func pauseResume(sender: AnyObject) {     
    if isPaused{
        timer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: Selector("somAction"), userInfo: nil, repeats: true)
        isPaused = false
    } else {
        timer.invalidate()
        isPaused = true
    }
}

如果你在寻找适用于Swift 2的方案,那么这个答案应该被采纳。它对我而言是有效的。 - Kent Bull

10

我之前也遇到了类似的问题,不过找到了一个简单的解决方法。

首先要指出像其他人所说的,Timer和NSTimer没有暂停功能。您必须使用Timer.invalidate()停止计时器。在无效化计时器后,必须重新初始化以启动计时器。引用来自https://developer.apple.com/documentation/foundation/timer的函数.invalidate() -

停止计时器再次触发并请求从其运行循环中删除它。


要暂停定时器,我们可以使用Timer.fireDate,这是Timer(和NSTimer)保存计时器将来触发的日期的位置。

以下是如何通过保存计时器直到下一次触发的剩余秒数来暂停计时器的方法。

//The variable we will store the remaining timers time in
var timeUntilFire = TimeInterval()

//The timer to pause
var gameTimer = Timer.scheduledTimer(timeInterval: delaysShow!, target: self, selector: #selector(GameClass.showRocket), userInfo: rocketid[i], repeats: false)

func pauseTimer()
{
    //Get the difference in seconds between now and the future fire date
    timeUntilFire = gameTimer.fireDate.timeIntervalSinceNow
    //Stop the timer
    gameTimer.invalidate()
}

func resumeTimer()
{
    //Start the timer again with the previously invalidated timers time left with timeUntilFire
    gameTimer = Timer.scheduledTimer(timeInterval: timeUntilFire, target: self, selector: #selector(GameClass.showRocket), userInfo: rocketid[i], repeats: false)
}

注意: 在获取fireDate之前不要使Timer失效。在调用invalidate()后,Timer似乎会将fireDate重置为2001-01-01 00:00:00 +0000。

第二个注意事项: Timer可能会在设置的fireDate之后触发。这将导致一个负数,Timer将默认在0.1毫秒后运行。https://developer.apple.com/documentation/foundation/timer/1412416-scheduledtimer


9

开始:

timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: Selector("updateView"), userInfo: nil, repeats: true)

恢复操作:

timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: Selector("updateView"), userInfo: nil, repeats: true)

暂停:

timer.invalidate

这对我有用。诀窍是不要寻找类似于"timer.resume""timer.validate"这样的东西。只需使用"相同的代码开始计时器"在暂停后恢复它。


9

开始

timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController.action), userInfo: nil, repeats: true)

暂停

timer.invalidate()

重置

time += 1
label.text = String(time)

'label'是输出时间计时器。


5
您无法恢复计时器。 相反,只需创建一个新的计时器。
class SomeClass : NSObject { // class must be NSObject, if there is no "NSObject" you'll get the error at runtime

    var timer = NSTimer()

    init() {
        super.init()
        startOrResumeTimer()
    }

    func timerAction() {
        NSLog("timer action")
    }

    func pauseTimer() {
        timer.invalidate
    }

    func startOrResumeTimer() {
        timer = NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: Selector("timerAction"), userInfo: nil, repeats: true)
    }
}

4
停止它。
  time3.invalidate() 

重新启动它
  time3.fire()

检查这个答案 https://dev59.com/WWkw5IYBdhLWcg3wUI_x - Christos Chadjikyriacou
@Christos Hadjikyriacou 当我输入“fire”时,什么都没有发生。有什么帮助吗? - Anton O.
1
我认为你应该重新初始化NSTimer。 - Christos Chadjikyriacou
13
根据苹果文档:“(invalidate)停止接收器的触发并请求将其从运行循环中移除。”一旦调用了invalidate,您应该将定时器设置为nil,然后重新实例化/启动以“重新启动”。 - preynolds
2
.fire() 不会重新启动计时器(也就是说,它将继续重复调用选择器)。为了实现这一点(这正是 OP 所指的“恢复”),您必须重新初始化计时器。 - Clay Ellis

3
尽管这里提供的解决方案很好,但我认为缺少了一个重要的见解。就像这里很多人所解释的那样,计时器invalidate()和重新创建是最佳选择。但有人可能会认为你可以像这样做:
var paused:Bool

func timerAction() {
    if !paused {
        // Do stuff here
    }
}

实现简单但效率较低。苹果因能源影响推荐尽量避免使用定时器,而是优先选择事件通知。如果确实需要使用定时器,应通过使当前定时器无效来高效实现暂停。阅读有关苹果能源效率指南中的定时器建议: https://developer.apple.com/library/content/documentation/Performance/Conceptual/EnergyGuide-iOS/MinimizeTimerUse.html

2

SWIFT3

全局声明:

 var swiftTimer = Timer()
 var count = 30
 var timer = Timer()
 @IBOutlet weak var CountDownTimer: UILabel!

viewDidLoad

override func viewDidLoad() { super.viewDidLoad() BtnStart.tag = 0 }

触发IBACTION:

@IBAction func BtnStartTapped(_ sender: Any) {
      if BtnStart.tag == 0 {
           BtnStart.setTitle("STOP", for: .normal)
           timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(ScoreBoardVC.update), userInfo: nil, repeats: true)

           BtnStart.tag = 1
      } else {

           BtnStart.setTitle("START", for: .normal)
           timer.invalidate()

           BtnStart.tag = 0
      }                    
 }

处理事物的函数:

func update(){

      if(count > 0){
           let minutes = String(count / 60)
           let ConvMin = Float(minutes)
           let minuttes1 = String(format: "%.0f", ConvMin!)

           print(minutes)
           let seconds = String(count % 60)
           let ConvSec = Float(seconds)
           let seconds1 = String(format: "%.0f", ConvSec!)

           CountDownTimer.text = (minuttes1 + ":" + seconds1)
           count += 1
      }          
 }

0

暂停计时器:timer.invalidate()

恢复计时器:重新创建计时器,它可以正常工作。

timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(mainController.updateTimer), userInfo: nil, repeats: true)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接