Reputation: 367
I have the following code:
class firstVC: UIViewController {
var timer : Timer?
func scheduledTimerWithTimeInterval(){
timer = Timer.scheduledTimer(timeInterval: 60, target: self,
selector: #selector(self.anotherFunc), userInfo: nil, repeats:
true)
}
override func viewDidAppear(_ animated: Bool) {
scheduledTimerWithTimeInterval()
}
}
I'm trying to stop the timer without success:
func stopTimer() {
if timer != nil {
timer?.invalidate()
timer = nil
}
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
stopTimer()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
stopTimer()
}
I even tried to put the stop function in applicationWillResignActive
And in applicationDidEnterBackground
but it didn't stop:
firstVC().stopTimer()
Your help will be appreciated, thank you.
Upvotes: 6
Views: 8639
Reputation: 61
Use this version, which doesn't retain self:
let timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { [weak self] _ in
self?.func()
})
And invalidate the timer in deinit:
deinit {
self.timer?.invalidate()
}
Upvotes: 0
Reputation: 2817
Nothing works for me, at last using self did the trick!!!
self.atimer?.invalidate()
self.atimer = Timer()
Upvotes: 1
Reputation: 367
After research I found a solution,
The only thing that worked for me is to create functions in AppDelegate file and call them when needed,
Here is the code, the timerSwitch function:
func timerSwitch()
{
if (timerStatus) {
checkStateTimer = Timer.scheduledTimer(
timeInterval: 60,
target:self,
selector: #selector(self.yourFunction),
userInfo: nil, repeats: true)
} else {
checkStateTimer?.invalidate()
}
}
func stopTimer()
{
timerStatus = false
timerSwitch()
}
func startTimer()
{
timerStatus = true
timerSwitch()
}
While 'yourFunction' is what you want to execute when the timer starts,
In my case is sending heartbeat.
Then I called the timerSwitch is the following functions in AppDelegate:
func applicationWillResignActive(_ application: UIApplication) {
stopTimer()
}
func applicationDidEnterBackground(_ application: UIApplication) {
stopTimer()
}
func applicationDidBecomeActive(_ application: UIApplication) {
startTimer()
}
Upvotes: 2
Reputation: 31
As a debugging step, try putting var timer = Timer()
in the global space (e.g. at the top of the file below the import
statements) to make sure there's only one Timer object being created and referred to. If you have the Timer
declaration within a function, you'll make a new timer each time you call that function, which causes you to lose the reference to the old one, and ultimately not stop it.
Upvotes: 0
Reputation: 131418
As others have said, you are creating multiple timers without killing the old one before starting a new one. You need to make sure you stop any current timer before starting a new one.
What I do is to make my timers weak. I then use the code `myTimer?.invalidate() before trying to create a new timer:
class firstVC: UIViewController {
weak var timer : Timer?
func scheduledTimerWithTimeInterval(){
timer?.invalidate()
timer = Timer.scheduledTimer(timeInterval: 60, target: self,
selector: #selector(self.anotherFunc), userInfo: nil, repeats:
true)
}
}
By making your timer weak, the only thing that keeps a strong reference to the timer is the run loop. Then, when you invalidate it, it immediately gets released and set to nil. By using optional chaining to call the invalidate method, it doesn't do anything if it's already nil, and stops it and causes it to go nil if it IS running.
Note that this approach only works if you create your timer in one shot using one of the scheduledTimer()
factory methods. If you try to create a timer first and then add it to the run loop, you have to use a strong local variable to create it or it gets released as soon as you create it.
Upvotes: 12
Reputation: 3033
The problem is your timer gets instantiated more than once, so the original timer loses its reference. Add a variable didStartTimer = false. And then in viewDidAppear do a validation, and then call the timer func. That should do it.
like this:
class firstVC: UIViewController {
var timer : Timer?
var didStartTimer = false
func scheduledTimerWithTimeInterval(){
timer = Timer.scheduledTimer(timeInterval: 60, target: self,
selector: #selector(self.anotherFunc), userInfo: nil, repeats:
true)
}
override func viewDidAppear(_ animated: Bool) {
if !didStartTimer {
scheduledTimerWithTimeInterval()
didStartTime = true
}
}
Upvotes: 2