Trouble canceling timers

Hello,
I am trying to cancel a timer when I leave a storyboard scene.
I create a local variable at the top of my code

local cancelTime  

and in my functions I place this line where I assign the variable to a timer

cancelTime=timer.performWithDelay(2000,returnFruit)  

When I exit the scene I add this part to see if there is a timer to cancel:

 if cancelTime~= nil then  
 timer.cancel(cancelTime)  
 end  

I have to do this cause when I exit the scene while the timer is still active it wants to call a function that is not there anymore after exiting the scene and gives me an error. I have several different functions where I assign cancelTime to a timer. There is never more than one timer active. So every time I run a function the cancelTime variable is assigned a new timer.
The thing is the timer is never cancelled in my new scene it still tries to call the function the timer was set to run. There is a timer assigned to cancelTime cause when I do not check for nil and there is no timer assigned it crashes. It tells me cancelTime is not a timer.

Any ideas on how I force my timers to stop? [import]uid: 100901 topic_id: 35086 reply_id: 335086[/import]

The trouble with always assigning a timer to the same variable is that you can’t be sure if it’s erased before you start a new one.

The safest way to operate is to use a table instead.

[code] – This is a way to use a global, but you could do local too if it’s declared before createScene
_G.myTimers = {}

– Make new timers like this:
– (Ensures each timer is a new entry!)
myTimers[#myTimers+1] = timer.performWithDelay(2000, returnFruit)

– Cancel on exit like this:
function scene:willExitScene(event) – in the willExitScene
– you could use exitScene but this is earlier in the exit process
if #myTimers > 0 then
for i = #myTimers, 1, -1 do
timer.cancel(myTimers[i])
myTimers[i] = nil
end
end
end[/code]

On exit, that code loops backwards through all of your timers, canceling and nil’ing out each one. You can even convert that into a function to call… [import]uid: 41884 topic_id: 35086 reply_id: 139523[/import]

Thanks for the reply,
But doing this results in the same error.
It still tries to finish the timer.
[import]uid: 100901 topic_id: 35086 reply_id: 139525[/import]

Okay, well that at least narrows it down a bit. You’re using the correct procedure to cancel a timer, but it seems that something else in your code is either causing the timer to restart or causing a new timer to take its place before leaving the scene.

Ideally it would be great if you could post the parts of your code here that use timers either way, ( encapsulate your code with < code > < / code> minus the spaces…). At the very least maybe show all of your timer code lines? …but if you can’t, I suggest this:

  1. Wherever you have a timer created, add a print statement next to it. print("Timer here!")

  2. Wherever you have a timer cancelled, add a print statement there too. print("Timer cancelled!")

This can help you figure out how often a timer is being called. Maybe you have one in a place that keeps getting retriggered. [import]uid: 41884 topic_id: 35086 reply_id: 139527[/import]

Well it must be something in my code. If I do this which is basically a distilled version of what I have in my code it works. Only thing that is weird is that it does print the print statement that shouldn’t be printed if I don’t cancel the timer. I have a purgeall and remove all in the new scene. But that is a different problem.

[code]


– scenetemplate.lua


local storyboard = require( “storyboard” )
local scene = storyboard.newScene()
local cancelTime


– NOTE:

– Code outside of listener functions (below) will only be executed once,
– unless storyboard.removeScene() is called.



– BEGINNING OF YOUR IMPLEMENTATION

local function switchScreen()
storyboard.gotoScene( “finish” )
end

local function timerStarter(event)
if event.phase == “began” then

local function delayer()
print (“This can’t show up, will crash before it can be printed”)
end
cancelTime=timer.performWithDelay(2000,delayer)
print(“start timer”)
end
return true
end

– Called when the scene’s view does not exist:
function scene:createScene( event )
local group = self.view

local button=display.newRect(group,100,100,50,50)

button:addEventListener(“touch”,timerStarter)

local exitButton=display.newRect(group,300,400,100,100)
button:addEventListener(“touch”,switchScreen)
exitButton:setFillColor(10, 100, 100)

– CREATE display objects and add them to ‘group’ here.
– Example use-case: Restore ‘group’ from previously saved state.


end
– Called immediately after scene has moved onscreen:
function scene:enterScene( event )
local group = self.view


– INSERT code here (e.g. start timers, load audio, start listeners, etc.)


end
– Called when scene is about to move offscreen:
function scene:exitScene( event )
local group = self.view


– INSERT code here (e.g. stop timers, remove listeners, unload sounds, etc.)


if cancelTime~= nil then
print(“cancelled timer”)
timer.cancel(cancelTime)
end
end
– Called prior to the removal of scene’s “view” (display group)
function scene:destroyScene( event )
local group = self.view


– INSERT code here (e.g. remove listeners, widgets, save state, etc.)


end


– END OF YOUR IMPLEMENTATION

– “createScene” event is dispatched if scene’s view does not exist
scene:addEventListener( “createScene”, scene )

– “enterScene” event is dispatched whenever scene transition has finished
scene:addEventListener( “enterScene”, scene )

– “exitScene” event is dispatched before next scene’s transition begins
scene:addEventListener( “exitScene”, scene )

– “destroyScene” event is dispatched before view is unloaded, which can be
– automatically unloaded in low memory situations, or explicitly via a call to
– storyboard.purgeScene() or storyboard.removeScene().
scene:addEventListener( “destroyScene”, scene )


return scene

[/code] [import]uid: 100901 topic_id: 35086 reply_id: 139556[/import]

I tested it with an exit button too that is why it is in the code. [import]uid: 100901 topic_id: 35086 reply_id: 139557[/import]

Taking a shot here, but you added 2 event listeners for the same button (line 45 and 48). I am assuming by the code that in line 48, it should be exitButton ?? [import]uid: 114363 topic_id: 35086 reply_id: 139567[/import]

Hi, I solved the problem. The screen was exited to quick, so the timer didn’t get assigned to cancelTIme. I added a delay of 100 before canceling the timer and it works now.
I added the two eventListeners to the same button so that when I press one button two functions run. So it would exit and cancel at the same time. Tried both versions but got tired of having to tap two buttons :wink:
[import]uid: 100901 topic_id: 35086 reply_id: 139630[/import]

The trouble with always assigning a timer to the same variable is that you can’t be sure if it’s erased before you start a new one.

The safest way to operate is to use a table instead.

[code] – This is a way to use a global, but you could do local too if it’s declared before createScene
_G.myTimers = {}

– Make new timers like this:
– (Ensures each timer is a new entry!)
myTimers[#myTimers+1] = timer.performWithDelay(2000, returnFruit)

– Cancel on exit like this:
function scene:willExitScene(event) – in the willExitScene
– you could use exitScene but this is earlier in the exit process
if #myTimers > 0 then
for i = #myTimers, 1, -1 do
timer.cancel(myTimers[i])
myTimers[i] = nil
end
end
end[/code]

On exit, that code loops backwards through all of your timers, canceling and nil’ing out each one. You can even convert that into a function to call… [import]uid: 41884 topic_id: 35086 reply_id: 139523[/import]

Thanks for the reply,
But doing this results in the same error.
It still tries to finish the timer.
[import]uid: 100901 topic_id: 35086 reply_id: 139525[/import]

Okay, well that at least narrows it down a bit. You’re using the correct procedure to cancel a timer, but it seems that something else in your code is either causing the timer to restart or causing a new timer to take its place before leaving the scene.

Ideally it would be great if you could post the parts of your code here that use timers either way, ( encapsulate your code with < code > < / code> minus the spaces…). At the very least maybe show all of your timer code lines? …but if you can’t, I suggest this:

  1. Wherever you have a timer created, add a print statement next to it. print("Timer here!")

  2. Wherever you have a timer cancelled, add a print statement there too. print("Timer cancelled!")

This can help you figure out how often a timer is being called. Maybe you have one in a place that keeps getting retriggered. [import]uid: 41884 topic_id: 35086 reply_id: 139527[/import]

Well it must be something in my code. If I do this which is basically a distilled version of what I have in my code it works. Only thing that is weird is that it does print the print statement that shouldn’t be printed if I don’t cancel the timer. I have a purgeall and remove all in the new scene. But that is a different problem.

[code]


– scenetemplate.lua


local storyboard = require( “storyboard” )
local scene = storyboard.newScene()
local cancelTime


– NOTE:

– Code outside of listener functions (below) will only be executed once,
– unless storyboard.removeScene() is called.



– BEGINNING OF YOUR IMPLEMENTATION

local function switchScreen()
storyboard.gotoScene( “finish” )
end

local function timerStarter(event)
if event.phase == “began” then

local function delayer()
print (“This can’t show up, will crash before it can be printed”)
end
cancelTime=timer.performWithDelay(2000,delayer)
print(“start timer”)
end
return true
end

– Called when the scene’s view does not exist:
function scene:createScene( event )
local group = self.view

local button=display.newRect(group,100,100,50,50)

button:addEventListener(“touch”,timerStarter)

local exitButton=display.newRect(group,300,400,100,100)
button:addEventListener(“touch”,switchScreen)
exitButton:setFillColor(10, 100, 100)

– CREATE display objects and add them to ‘group’ here.
– Example use-case: Restore ‘group’ from previously saved state.


end
– Called immediately after scene has moved onscreen:
function scene:enterScene( event )
local group = self.view


– INSERT code here (e.g. start timers, load audio, start listeners, etc.)


end
– Called when scene is about to move offscreen:
function scene:exitScene( event )
local group = self.view


– INSERT code here (e.g. stop timers, remove listeners, unload sounds, etc.)


if cancelTime~= nil then
print(“cancelled timer”)
timer.cancel(cancelTime)
end
end
– Called prior to the removal of scene’s “view” (display group)
function scene:destroyScene( event )
local group = self.view


– INSERT code here (e.g. remove listeners, widgets, save state, etc.)


end


– END OF YOUR IMPLEMENTATION

– “createScene” event is dispatched if scene’s view does not exist
scene:addEventListener( “createScene”, scene )

– “enterScene” event is dispatched whenever scene transition has finished
scene:addEventListener( “enterScene”, scene )

– “exitScene” event is dispatched before next scene’s transition begins
scene:addEventListener( “exitScene”, scene )

– “destroyScene” event is dispatched before view is unloaded, which can be
– automatically unloaded in low memory situations, or explicitly via a call to
– storyboard.purgeScene() or storyboard.removeScene().
scene:addEventListener( “destroyScene”, scene )


return scene

[/code] [import]uid: 100901 topic_id: 35086 reply_id: 139556[/import]

I tested it with an exit button too that is why it is in the code. [import]uid: 100901 topic_id: 35086 reply_id: 139557[/import]

Taking a shot here, but you added 2 event listeners for the same button (line 45 and 48). I am assuming by the code that in line 48, it should be exitButton ?? [import]uid: 114363 topic_id: 35086 reply_id: 139567[/import]

Hi, I solved the problem. The screen was exited to quick, so the timer didn’t get assigned to cancelTIme. I added a delay of 100 before canceling the timer and it works now.
I added the two eventListeners to the same button so that when I press one button two functions run. So it would exit and cancel at the same time. Tried both versions but got tired of having to tap two buttons :wink:
[import]uid: 100901 topic_id: 35086 reply_id: 139630[/import]