SSK2: Does listen("enterframe", obj) require ignore() or....

Hi Ed,

Supposing I have a code that looked like this:

for i = 1, #numEnemies do enemy[i].enterFrame = function (self) if gamePaused then return true end --do this --do that end listen("enterFrame", enemy[i]) end

My questions are:

  1. Is the listener automatically deleted when I remove it’s parent object?  (eg. enemy[2]:removeSelf(); enemy[2]=nil) ?   Or do I need to call ignore(“enterFrame”, enemy[2]) before removing the object enemy[2]? 

  2. What is the best way to delete and housekeep all these listeners and where shall I do it?   

Thanks,

santi

Nope.   enterFrame listeners and other global listeners are not automatically removed.

However, since you’re using SSK, there is an easy fix.

Do this:

-- Finalize listener - Called when object is destroyed. local function onFinalize( self ) -- name is not important, this is my convention ignoreList( {"enterFrame"}, self ) end -- If your enterFrame listeners all do the same thing, just -- create a single function and re-use it. local function onEnterFrame( self ) -- name is not important, this is my convention if gamePaused then return true end --do this with 'self' --do that with 'self' end for i = 1, #numEnemies do enemy[i].enterFrame = onEnterFrame enemy[i].finalize = onFinalize listen("enterFrame", enemy[i]) enemy[i]:addEventListener("finalize") end

I’m re-pasting this code using PURE corona for future readers and so you can see the difference.

-- Finalize listener - Called when object is destroyed. local function onFinalize( self ) -- name is not important, this is my convention Runtime:removeEventListener( "enterFrame", self ) end -- If your enterFrame listeners all do the same thing, just -- create a single function and re-use it. local function onEnterFrame( self ) -- name is not important, this is my convention if gamePaused then return true end --do this with 'self' --do that with 'self' end for i = 1, #numEnemies do enemy[i].enterFrame = onEnterFrame enemy[i].finalize = onFinalize Runtime:addEventListener( "enterFrame", enemy[i] ) enemy[i]:addEventListener( "finalize" ) end

The two major differences are:

  • ‘Runtime:addEventListener()’ is simply ‘listen()’ in SSK which is much easier to type.
  • ‘Runtime:removeEventListener()’ is replaced by ‘ignoreList()’ in the prior code.
    • The direct SSK equivalent is actually ‘ignore()’  (again easier to type).

Why Use ignoreList()?

If you write your code the way I suggested:

local function onEnterFrame( self ) end ... then later obj.enterFrame = onEnterFrame .. and finally listen( "enterFrame", obj )

You can use ‘ignoreList()’ instead of ‘ignore()’. 

It has a couple of nice features:

  1. It is safer and will not attempt to ignore an event that was never listened for or has otherwise already had the listener removed.
  • If you try to call Runtime:removeEventListener() twice on a object, the second call will crash.  ‘ignoreList()’ is smart enough to avoid this.
  1. You can list all of global listeners you want to ignore in one line.

Example of #2.  Let’s assume you are also listenering for ‘mouse’ and ‘accelerometer’, you could then do this:

ignoreList( { "enterFrame", "mouse", "accelerometer" }, obj )

Awesome!  That did the trick.  

Thanks a lot Ed.   

One more thing,  on the finalize listener, when you said “Called when object is destroyed”… 

does that mean a standard  obj:removeSelf();  obj=nil  triggers it?  

Thanks!

Yes.  All of these will trigger it:

display.remove(obj) .. and obj:removeSelf() .. and if it is in a group group:insert( obj ) .. then if you remove the group it is also called display.remove(group)

Perfect!!  Thanks again.

Wow, this is a pretty nice topic, definitely saving this.

Nope.   enterFrame listeners and other global listeners are not automatically removed.

However, since you’re using SSK, there is an easy fix.

Do this:

-- Finalize listener - Called when object is destroyed. local function onFinalize( self ) -- name is not important, this is my convention ignoreList( {"enterFrame"}, self ) end -- If your enterFrame listeners all do the same thing, just -- create a single function and re-use it. local function onEnterFrame( self ) -- name is not important, this is my convention if gamePaused then return true end --do this with 'self' --do that with 'self' end for i = 1, #numEnemies do enemy[i].enterFrame = onEnterFrame enemy[i].finalize = onFinalize listen("enterFrame", enemy[i]) enemy[i]:addEventListener("finalize") end

I’m re-pasting this code using PURE corona for future readers and so you can see the difference.

-- Finalize listener - Called when object is destroyed. local function onFinalize( self ) -- name is not important, this is my convention Runtime:removeEventListener( "enterFrame", self ) end -- If your enterFrame listeners all do the same thing, just -- create a single function and re-use it. local function onEnterFrame( self ) -- name is not important, this is my convention if gamePaused then return true end --do this with 'self' --do that with 'self' end for i = 1, #numEnemies do enemy[i].enterFrame = onEnterFrame enemy[i].finalize = onFinalize Runtime:addEventListener( "enterFrame", enemy[i] ) enemy[i]:addEventListener( "finalize" ) end

The two major differences are:

  • ‘Runtime:addEventListener()’ is simply ‘listen()’ in SSK which is much easier to type.
  • ‘Runtime:removeEventListener()’ is replaced by ‘ignoreList()’ in the prior code.
    • The direct SSK equivalent is actually ‘ignore()’  (again easier to type).

Why Use ignoreList()?

If you write your code the way I suggested:

local function onEnterFrame( self ) end ... then later obj.enterFrame = onEnterFrame .. and finally listen( "enterFrame", obj )

You can use ‘ignoreList()’ instead of ‘ignore()’. 

It has a couple of nice features:

  1. It is safer and will not attempt to ignore an event that was never listened for or has otherwise already had the listener removed.
  • If you try to call Runtime:removeEventListener() twice on a object, the second call will crash.  ‘ignoreList()’ is smart enough to avoid this.
  1. You can list all of global listeners you want to ignore in one line.

Example of #2.  Let’s assume you are also listenering for ‘mouse’ and ‘accelerometer’, you could then do this:

ignoreList( { "enterFrame", "mouse", "accelerometer" }, obj )

Awesome!  That did the trick.  

Thanks a lot Ed.   

One more thing,  on the finalize listener, when you said “Called when object is destroyed”… 

does that mean a standard  obj:removeSelf();  obj=nil  triggers it?  

Thanks!

Yes.  All of these will trigger it:

display.remove(obj) .. and obj:removeSelf() .. and if it is in a group group:insert( obj ) .. then if you remove the group it is also called display.remove(group)

Perfect!!  Thanks again.

Wow, this is a pretty nice topic, definitely saving this.