快速无效计时器不起作用
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()
函数时(viewWillAppear
,viewDidAppear
,...)
因此,简而言之,如果您不确定(或无法保证)您的 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,所以我已经回答了这个环境以上是关于快速无效计时器不起作用的主要内容,如果未能解决你的问题,请参考以下文章