快速无效计时器不起作用

Posted

技术标签:

【中文标题】快速无效计时器不起作用【英文标题】: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 但实际上什么都不做。 【参考方案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,所以我已经回答了这个环境

以上是关于快速无效计时器不起作用的主要内容,如果未能解决你的问题,请参考以下文章

QWebEngineView:计时器在可见时不起作用

为啥 MIDI 音符计时不起作用?

嵌套的计时器代码不起作用

刷新 JComponent 倒计时不起作用

Matlab 计时器在独立应用程序中不起作用

.gitignore不起作用/无效,.idea文件夹无法删除