【问题标题】:swift invalidate timer doesn't work快速无效计时器不起作用
【发布时间】:2016-04-03 03:29:43
【问题描述】:

我有这个问题好几天了,我不明白我做错了什么。

我的应用程序基本上只是创建了一些计时器。我需要阻止它们并创建新的。但目前阻止它们不起作用。

self.timer = NSTimer.scheduledTimerWithTimeInterval(timeInterval, target:self, selector: "timerDidEnd:", userInfo: "Notification fired", repeats: false)

这是我的计时器

func timerDidEnd(timer:NSTimer){
    createUnrepeatedAlarmWithUpdateInterval()
}

因为我的计时器不想停止,我目前正在使用不重复的计时器并在它停止后自己启动它。

func stopAlarm() {

    if self.timer != nil {
        self.timer!.invalidate()
    }
    self.timer = nil
    self.timer = NSTimer()
}

这就是我停止计时器的方式。

alarmManager.stopAlarm()
alarmManager.createUnrepeatedAlarmWithUpdateInterval()

我在创建新计时器之前调用了stopAlarm() 函数。

我真的不知道我做错了什么,所以我很感激每一个答案:)

class AlarmManager: ViewController{

private var timer : NSTimer?
private var unrepeatedTimer : NSTimer?
private let notificationManager = NotificationManager()
private var current = NSThread()
private let settingsViewController = SettingsViewController()

func createRepeatedAlarmWithUpdateInterval(){

    var timeInterval:NSTimeInterval = settingsViewController.getUpdateIntervalSettings()

    if timer == nil{
    timer = NSTimer.scheduledTimerWithTimeInterval(timeInterval,
        target: self,
        selector: "repeatedTimerDidEnd:",
        userInfo: "Notification fired",
        repeats: true)
    }
}
func repeatedTimerDidEnd(repeatedTimer:NSTimer){
    ConnectionManager.sharedInstance.loadTrainings(settingsViewController.getServerSettings())
    createUnrepeatedAlarm(10)
}

func createUnrepeatedAlarm(timeInterval:Double){

    unrepeatedTimer = NSTimer.scheduledTimerWithTimeInterval(timeInterval,
        target: self,
        selector: "unrepeatedTimerDidEnd:",
        userInfo: "Notification fired",
        repeats: false)
}
func unrepeatedTimerDidEnd(unrepeatedTimer:NSTimer){
    notificationManager.createNotification(self, reminderType: NotificationManager.ITEMRATINGREMINDER)
    notificationManager.createNotification(self, reminderType: NotificationManager.ITEMREMINDER)
    print("UnrepeatedAlarm ended")
}

func stopAlarm(){
    print("StopAlarm triggered")
    if (timer != nil)
    {
        print("stoptimer executed")
        timer!.invalidate()
        timer = nil
    }

    if (unrepeatedTimer != nil)
    {
        unrepeatedTimer!.invalidate()
        unrepeatedTimer = nil
    }
}
}

这就是这个类的全部代码。也许这有帮助:D

【问题讨论】:

  • 您确定计时器不会停止吗?会不会是您正在创建多个计时器?
  • 确保从主线程调用stopAlarm()
  • @MariusFanu 我肯定会从主线程调用 stopAlarm。我打印了线程以确保它是同一个。
  • @Cristik 如果执行 timerDidEnd 我打印出一行,所以我知道它确实结束了。如果我在同一线程上使用 stopAlarm() 之后,无论如何都会打印出该行。所以我认为计时器不会停止。我也不认为在这种情况下可以创建多个计时器,因为我总是使用相同的变量,所以它会被覆盖,对吧? :D
  • 没有错,但没有意义。如果计时器没有运行,它应该是nil。通用实例 NSTimer() 不是 nil 但实际上什么都不做。

标签: ios swift nstimer


【解决方案1】:

安全启动和停止计时器的常用方法是

var timer : Timer?

func startTimer()
{
  if timer == nil {
    timer = Timer.scheduledTimer(timeInterval: timeInterval, target: self, selector: #selector(timerFired), userInfo: nil, repeats: true)
  }
}

func stopTimer()
{
  if timer != nil {
    timer!.invalidate()
    timer = nil
  }
}

startTimer() 仅当它是 nil 时才启动计时器,stopTimer() 仅当它不是 nil 时才停止它。

您只需在创建/启动新计时器之前停止计时器。

【讨论】:

  • 这基本上就是我正在做的。我认为我的问题出在其他地方。我在执行 stopTimer() 时打印了一行,并在 if 内打印了一行。我从来没有在我的输出中看到 if 内的行,所以我从来没有进入过 if。所以问题是我的如果。帮助? :D
  • 您的代码看起来有点混乱,“重复”计时器实际上也没有重复。使用我的代码尝试重复计时器。
  • 我没有重复计时器。它们都是不重复的。我在我的问题上面写了几行。问题不在于计时器的创建或未使用 stopTimer() 或其他原因。就是“如果计时器!= nil”永远不会是真的。这是为什么呢?
  • 好的,我将其更改为重复警报,但仍然是同样的问题。当然如此。因为问题仍然是它没有使用if。我更新了我的问题中的代码,所以你可以告诉我我在 if 中做错了什么:D
  • 如果计时器 nil,您不必将其无效。我建议设置断点并查看变量的状态
【解决方案2】:

确保您在与计时器相同的线程上调用 invalidate。

来自文档:

特别注意事项 您必须从安装了计时器的线程发送此消息。如果您从另一个线程发送此消息,与计时器关联的输入源可能不会从其运行循环中删除,这可能会阻止线程正常退出。

https://developer.apple.com/documentation/foundation/nstimer/1415405-invalidate?language=objc

【讨论】:

  • 如果你使用block闭包设置定时器,使block内的定时器失效
  • 很高兴知道如何引用创建它的线程
  • 谢谢。这是我的问题,最终在同一个选择的线程上创建和销毁显示链接并且它有效。
【解决方案3】:

前面的答案没有真正涵盖的一点是,您应该小心您的计时器没有被多次安排。

如果您多次安排一个计时器而不首先使其无效,它最终会安排在多个运行循环上,然后使其无效几乎是不可能的。

对我来说,它发生在我的视图控制器生命周期中的单独函数中调用我的 scheduleTimer() 函数时(viewWillAppearviewDidAppear,...)

因此,简而言之,如果您不确定(或无法保证)您的 Timer 只安排一次,请始终先使其无效。

【讨论】:

  • 这是我的问题!我没有意识到我已经在几个不同的地方安排了时间。我现在有一个来电者,它按预期停止了。谢谢!
【解决方案4】:

我已经尝试了所有可能的解决方案,但最终无法解决我在初始化计时器时设置了重复“false”,如下所示

self.timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(viewcontroller.methodname), userInfo: nil, repeats: false)

并且需要在我的选择器方法中添加以上行,无论我想要重复时间的条件。

例如:- 我的要求是我想重复调用某个方法,直到满足一个条件。因此,我没有添加重复 true,而是将其设置为 false,因为在我的情况下,repeat true 不会使计时器无效。

我在 viewdidload 方法中添加了下面

self.timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(viewcontroller.method), userInfo: nil, repeats: false)

在选择器函数中我添加了下面的代码

@objc func 方法{

if condition not matched{
   self.timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(viewcontroller.method), userInfo: nil, repeats: false)
 }
 else{
    // once you are here your timer invalidate automatically
 }

}

希望这能解决您的问题

【讨论】:

    【解决方案5】:

    对于 Swift 5 Xcode 12.4,有一个使用计时器的示例:

    class MyController: UIViewController {
    
        private id: Float;
    
        func setValue(_ value: Float, withAnimation: Bool) {
                
                let step: Float = value / 200
                var current: Float  = withAnimation ? 0.0 : value
                
                let _ = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: withAnimation) { timer in
                    
                    DispatchQueue.main.async {
                        
                        self.id = current
                        
                        current += step
                        
                        if current > value || withAnimation == false {
                            self.id = current
                            
                            timer.invalidate()
                        }
                    }
                }
            }
    }
    

    【讨论】:

    • 你能解释一下这是做什么的吗?我对 Swift 还是很陌生,我正在为 macOS 写作。我也有这个问题,我想我理解你的回答中发生的一些事情。我只是不明白这是如何工作的。
    • 奇怪,因为问题标记为 iOS。在示例中,我们使用 Timer 创建了计时器。 scheduleTimer 类方法,作为此调用的最后一个参数,我们提供了一个闭包(函数),如果 repeats 为真,它将每次调用,如果不是,则只调用一次。在这个闭包中,我们检查当前值是否 > value 或 withAnimation 是否为 false,如果是则使计时器无效,则无效是停止并释放计时器。希望它解释一下。
    • 我想我明白了,但是没有从类的主体调用这个方法的用例。现在我的方法是func startTimer() {if Thread.isMainThread { timer?.invalidate() timer = nil timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(updateViewsWithTimer), userInfo: nil, repeats: true)},我的代码只是在需要触发时调用 startTimer()。当我需要它停止时,我尝试使用timer.invalidate(); timer = nil
    • 我还收到一个错误,即 ViewController 没有成员“项目”。我知道 OP 将其用于 iOS,但我想将其调整为 macOS。
    • 这只是示例如何使用,您需要根据自己的情况采用它。主要思想是创建带有闭包的计时器,并在闭包内使用条件来关闭计时器。这个问题被标记为 iOS,所以我已经回答了这个环境
    猜你喜欢
    • 2019-08-28
    • 2016-12-23
    • 1970-01-01
    • 1970-01-01
    • 2015-12-28
    • 2016-11-16
    • 1970-01-01
    • 2021-06-30
    • 2021-11-04
    相关资源
    最近更新 更多