How to remove listeners by iterating over the table?

A similar question. Tell me what I’m doing wrong. In some function, in a loop (10x10 matrix creation), I create objects and hang listeners, I put the objects in a table:

for i = 1, 10 do
for j = 1, 10 do
playerCell: addEventListener (“tap”, placeSph)
playerTab [i] [j] = playerCell
end
end

In another function, I wanted to remove the listeners with this code:

for i = 1, #playerTab do
for j = 1, #playerTab [i] do
playerTab [i] [j]:removeEventListener (“tap”, placeSph)
end
end

Returns nil, does not remove the listener. Maybe I’m calling incorrectly via :

Is the error this, “attempt to index field ‘?’ (a nil value)”?

If yes, maybe the codes below may help. If not, what is the error message?

--add listeners
for i = 1, 10 do
    playerTab[ i ] = {}
    for j = 1, 10 do
	    playerCell:addEventListener( "tap", placeSph )
	    playerTab[ i ][ j ] = playerCell
    end
end
--	remove listeners 
for i = 1, #playerTab do
	for j = 1, #playerTab[ i ] do
		playerTab[ i ][ j ]:removeEventListener ( "tap", placeSph )
	end
end

When you know in advance how many nested tables there are, you can initialize them with one line. Not in a loop.

playerTab = {{}, {}, {}, {}, {}, {}, {}, {}, {}, {}}

Sorry, I forgot to indicate. Yes, of course I create a matrix like in your example (I just skipped a line of code when I wrote the question).

There are no error messages, just removeEventListener returns nil. And the listener, accordingly, is still working.

Your approach is correct.

Are you sure you still have the reference to placeSph ??

If you lost or changed the reference contained by placeSph the removeEventListener won’t take effect.

1 Like

@yashureg Avoid this kind of table creation if possible, since it can lead to some mistakes.

@luantiang approach is better because if you decide to change the number of rows or cols you don’t need to count how many nested tables you already have and add more manually. You may also forget to do that or count them wrong.

1 Like

You are correct print (placeSph) gives nil value. I think I have a knowledge gap about this. Did the garbage collector destroy the reference to placeSph? It was declared as a local function in the main file along with other functions that work. Is this connected with the fact that placeShp is hung on the playerCell, which are accessed only as an element of the table in which I put all of them?

The garbage collector clean the memory that is not being referenced by any variable, and it doesn’t break references by its own.

If the declaration and use of placeSph is in the same file, this should be happening because of closures. If you are declaring it inside a function, it is going to be accessible only inside that function. Make sure to declare it in the same or in a higher closure to be accessible when you remove the event listeners.

Also, try to avoid keeping all your code in main.lua.

Main must be only the initialization file of all your game. And your files must rarely be over 1000 lines. It will help you debugging and keeping your code clean.

** Somewhat off topic suggestion **

If you are removing these listeners just before you delete the object, then do it the easy way, use a finalize listener to do the cleanup.

Here is a standalone example of a display object, cleaning up:

  • Local Listener - Touch listener for this example.
  • Outstanding Timer
local function onTouch( self, event )
  -- body of listener
end

local function onFinalize( self, event )
   self:removeEventListener( 'touch' )
   timer.cancel(self.myTimer)
end


local obj = display.newCircle( ... )

-- Adding the touch listener (local style listener)
obj.touch = onTouch
obj:addEventListener( 'touch' )

-- Start a timer and track the handle in field on object
obj.myTimer = timer.peformWithDelay( 10000, function() ... end )

... later, just delete the object and it will clean up after itself

display.remove( obj )

No, I am not writing in main. In the file with the screen of the immediate game, I have declared all the functions one by one as local function. That is, the declaration of the placeSph function is no different from the rest. Probably the problem is what I am doing:

local function playerField ()
for i = 1, 10 do
for j = 1, 10 do
local playerCell = display.newImageRect( mainGroup, objectSheet, 10, cellSize, cellSize )
playerCell:addEventListener( “tap”, placeSph )
playerTab[i][j] = playerCell
end
end
end

Should I declare playerCell outside of the for loop, or even outside of this function as a local variable?

I am not deleting objects. The idea was that I create a field of game cells on which the player places objects (like in a sea battle game). Until the number of objects exceeds 6, the listener adds them (individual objects on top of the cells are simply at the same coordinates). As soon as there are 6 of them, the game with AI starts automatically and the listener is not needed on the player’s field (he has already set everything, and AI just randomly selects a cell and checks or sets its properties).