Ludicrous Software

Fastest Way to Remove All Event Listeners

Removing the event listeners that you’ve created is key to avoiding memory leaks in your Corona applications. Here’s a simple little function that will remove all of the event listeners attached to a particular object.

1
2
3
4
function removeAllListeners(obj)
  obj._functionListeners = nil
  obj._tableListeners = nil
end

The function takes as its argument the object for which you want to remove the listeners. This would typically be a display object, but could also be the global Runtime object - basically anything that could have event listeners attached to it.

After looking at that function, you’re probably asking, “That’s great, but where did these _functionListeners and _tableListeners tables come from, and how did they get the information about the listeners in the first place?” They’re built-in properties of objects that listen for events. Since they start with an underscore, they’re meant to be somewhat private properties, but they’re completely accessible. In an object that has no event listeners, those tables don’t exist, so by setting their values to nil, we’re effectively returning the object to its pre-event listener state.

This sort of thing would be handy if you’re creating objects dynamically, such that they may have a different set of event listeners depending on their specific role. Rather than create a separate property to track the event listeners you need to remove, you can use the above function to take care of this clean-up for you. One word of warning: since these are semi-private properties that aren’t really meant to be exposed, it’s possible that Ansca will at some point change how things work under the hood, and this may stop working. So use at your own risk, etc., etc.

(Also, I’m not suggesting the approach I just described is the best way to architect your application, but it’s possible. And you may want to use this function for extra assurance that you got all the event listeners that were added. I’m just reporting my findings here; what you do with it is up to you!)

If you’re interested: I found out about these tables while playing around with the debugger, specifically the dump command, which as I mentioned in my last post, can yield some interesting findings (There’s also this post on the Ansca forums that shows a whole bunch of information via straight Lua code, rather than using the debugger). If you attach function listeners to an object, you’ll see something like this in the debugger:

1
2
3
4
5
6
7
> dump square
square(table: 0x1c320e0) =
{
  _proxy = userdata: 0x1c320d4
  _class = table: 0x1c1d8f0
  _functionListeners = table: 0x1c36580
}

And there’s _functionListeners. dump that, and here’s what you see:

1
2
3
4
5
> dump square._functionListeners
square._functionListeners(table: 0x1c36580) =
{
  touch = table: 0x1c37590
}

As you can see, the _functionListeners table uses the name of the event to listen for as the key, and the value is a table. You might think that the value would be a function instead of a table, but since you can attach multiple listeners for a single event, Corona uses a table to store all of those listeners. Here’s the output from an object that has multiple touch event listeners:

1
2
3
4
5
6
> dump square._functionListeners.touch
square._functionListeners.touch(table: 0x1a27820) =
{
  1 = function: 0x1a23420
  2 = function: 0x1a23910
}

So, you could use pairs() and ipairs() on these tables to iterate through them and remove listeners selectively. You can also use table.insert() to add event listeners if you so chose. Setting the tables to nil results in the wholesale removal of listeners.