removing display objects from memory without inserting in self.view

I feel like there’s some powerful mojo here, both in the question and the answer. I’ve been spending a lot of time working with storyboard and external modules and this seems very applicable to my efforts.

Am I understanding this correctly that the goal is to be able to reference the storyboard group in the module?

Brent, in your example I see that the myGroup group is passed and the putInGroup value gets set to that. I lose the example there though. How does putInGroup get utilized in the module?

Also, a question I’ve thought of looking at your example Brent. What would be the difference between these two ways of setting the LD.startListener value?:
[lua]
LD.startListener = startListener[/lua]or
[lua]
LD.startListener = startListener()
[/lua]

I’ve been using function brackets whenever I set a module table with a function and I’m wondering if I should be doing that without them the way that you have it in your sample?

Thanks :slight_smile: [import]uid: 105707 topic_id: 35817 reply_id: 143241[/import]

For reference, here is what I have so far:

--level1.lua  
display.setStatusBar ( display.HiddenStatusBar )  
local LD = require("linedraw")  
local removeAll  
local myGroup  
  
local function start()  
myGroup = display.newGroup()  
LD.startListener( myGroup )  
local button = display.newCircle( 0,0,50)  
button.x = display.contentWidth\*0.5; button.y = display.contentHeight-25  
button:setFillColor(255, 23, 75)  
button:addEventListener("tap", removeAll)  
myGroup:insert( button )  
 end  
function removeAll()   
 LD.endListener()  
 display.remove( myGroup )  
 myGroup = nil  
 timer.performWithDelay(1000,start)  
 return true  
end  
  
--INIT--  
start()  
  
-----------------------------  
--linedraw.lua  
local LD = {}  
  
local putInGroup --up-reference to the dedicated display group  
   
local function erase( event )  
 display.remove( event ) ; event.trans = nil ; event = nil  
end  
   
local function drawDots(args )  
   
 local dot = display.newCircle( putInGroup,0,0,10 ) ; dot:setFillColor(255,255,255)  
 dot.x = math.random(0,320) ; dot.y = math.random(-44,524)  
 dot.trans = transition.to( dot, {alpha=0.5, time=2000, onComplete=erase })  
 dot:toBack()  
 if args == "cancel" then   
 transition.cancel(dot.trans)  
 dot.trans = nil  
 print("tansition cancelled!")  
 end  
  
end  
   
function LD.startListener( myDisplayGroup )  
 Runtime:addEventListener("touch", drawDots)  
 putInGroup = myDisplayGroup  
end  
  
function LD.endListener()  
 drawDots("cancel")  
 Runtime:removeEventListener("touch", drawDots)  
end  
  
return LD  

I’m just trying to accomplish removing the dots created with linedraw.lua when operating from level1.lua.

The red button is a “reset” button.

EDITED: removed globals [import]uid: 73951 topic_id: 35817 reply_id: 143823[/import]

Here is a question:

Why am I unable to add objects to the dedicated display group using a 2nd independent function within linedraw.lua?

--linedraw.lua  
function LD.drawDot2()  
  
 local dot2 = display.newCircle(0,0,25 ) ; dot2:setFillColor(255,200,80)  
 dot2.x = math.random(-32,352) ; dot2.y = math.random(-44,524)  
 putInGroup:insert(dot2)  
end  
  
LD.drawDot2()  
  

I get: “attempt to index upvalue ‘putInGroup’ (a nil value)”.

In my testing, it appears that only one function at a time can access the passed display group.

That is, unless one tries to fire LD.drawDot2 from level1.lua.

I’d really like it if all functions within linedraw.lua were aware of the passed display group, so that I could work within linedraw.lua as well.

Idea:

I guess I could wrap the entire module in a master function and pass the display group into there, but there has to be a better way. [import]uid: 73951 topic_id: 35817 reply_id: 144373[/import]

local function drawDots( group )  
 local dot = display.newCircle( putInGroup,0,0,10 ) ; dot:setFillColor(255)  
 dot.x = math.random(0,300) ; dot.y = math.random(0,600)  
 dot.trans = transition.to( dot, {alpha=0.5, time=300, onComplete=erase })   
end  

Why is it necessary to have “(group)” in this function? [import]uid: 73951 topic_id: 35817 reply_id: 143563[/import]

Hi Mort,
Looks like that’s a tiny error… that argument is not needed. I must have put it in there thinking I’d pass a group to the “drawDots” function directly, but in fact, I just start the touch event listener. :slight_smile:

Brent [import]uid: 200026 topic_id: 35817 reply_id: 143607[/import]

Small request: would you mind editing the code above to fix the tiny error? I’ve found that it’s helpful to people who may use this thread as a reference later on.
@EHO: See this thread for an explanation of the reference LD.startListener = startListener : http://www.coronalabs.com/blog/2011/09/05/a-better-approach-to-external-modules/ [import]uid: 73951 topic_id: 35817 reply_id: 143640[/import]

Hi mort, the edit is made. Thanks for pointing it out. [import]uid: 200026 topic_id: 35817 reply_id: 143643[/import]

@Brent So, is it safe to assume that if one removes MyGroup from within level1.lua, said generated objects passed through linedraw.lua will be freed from memory (excluding those already removed)?

[import]uid: 73951 topic_id: 35817 reply_id: 143670[/import]

Hi @mort,
When I tested this, the display objects added to “myGroup” are removed properly, and from memory. Of course, standard cleanup processes still apply, like canceling timers or transitions, removing them from any external “reference tables”, etc.

On that note, I just updated my code sample and took out the fade transition on the “dots”… mostly to make this clearer and not pollute this core process with an aspect that some people won’t need.

Brent [import]uid: 200026 topic_id: 35817 reply_id: 143774[/import]

Hi @mort,
With the modification, try putting some objects in the group (in “linedraw.lua”) and then, from “level1.lua”, remove the group… those objects should be deleted and memory cleared. If they’re not, let me know and I’ll test some things out memory-wise on my end.

Brent [import]uid: 200026 topic_id: 35817 reply_id: 143809[/import]

Great. Now, since auto-cleanup is gone (within linedraw.lua), how would one go about removing said lines using level1.lua?

My approach

  1. Passing group to linedraw.lua to capture created objects (We’ve done this, right?). ?

  2. Destroying said objects whilst in level1.lua. See where I’m going? I’d like to pass arguments through external modules for object creation, whilst managing the removal of objects from my original level module.


Think of the modules such as linedraw.lua as filters through which I run data.

Structure:
main.lua
|
level 1.lua level 2. lua …etc.
\ /

functions.lua, linedraw.lua (just to use the current example, I’m not actually drawing lines in my project), character.lua

Would it be just the removal of “myGroup” and would there be anything one must nil out? [import]uid: 73951 topic_id: 35817 reply_id: 143805[/import]

Yes, that’s the idea. I can test this later tonight to ensure the memory is clearing properly… [import]uid: 200026 topic_id: 35817 reply_id: 143814[/import]

Much appreciated, I’ll get back to you if I have any other concerns as well! Thanks again. I’m just trying to make a reliable template/structure for managing objects. I don’t like having duplicate code in every single one of my modules, too much room for error. Let me know if there are any concerns one may have when it comes to upvalues and external references that may impeded object cleanup. That’s another thing that’s bugging me. [import]uid: 73951 topic_id: 35817 reply_id: 143816[/import]

@Brent, correct me if I’m wrong, but aren’t the dots we created in module, linedraw already in the group “myGroup” in module, level1?

Would display.remove( myGroup ); myGroup = nil suffice in removing the drawn dots from memory?
EDIT: I meant display.remove … oops! [import]uid: 73951 topic_id: 35817 reply_id: 143812[/import]

Hi @mort,
I just tested out my module (from the original code) and the memory is clearing properly when the group is removed. I see you’re adding more functionality to it, like canceling the timers and such, and that’s fine.

I would suggest you localize your variables and functions though, i.e. myGroup, function “removeAll”, functions “ld.startListener” and “ld.endListener”, etc. I just stay away from global entirely now… I suppose some globals are OK, but I do everything within my power to avoid them.

If in doubt, you should try to just check your memory in the routine, and see how the numbers print out over time. This is the function I use:

local function garbagePrinting()  
 collectgarbage("collect")  
 local memUsage\_str = string.format( "MEMORY = %.3f KB", collectgarbage( "count" ) )  
 print( memUsage\_str, "TEXTURE = "..(system.getInfo("textureMemoryUsed")/1000000) )  
end  
timer.performWithDelay( 1000, garbagePrinting, 0 )  

Brent [import]uid: 200026 topic_id: 35817 reply_id: 143940[/import]

I thought the LD.startListener/LD.endListener, using my method, are localized into the table LD? [import]uid: 73951 topic_id: 35817 reply_id: 143963[/import]

Yes, you’re right… I just noticed how you declare them now. My mistake. :slight_smile: [import]uid: 200026 topic_id: 35817 reply_id: 143965[/import]

Hi @mort,
How is this coming along for you? Did you find a better solution? I have one idea that I tested briefly which basically entails creating a “instantiate display group” function within “linedraw.lua”… essentially it just sets up the display group you send to the module, and then other functions can utilize it. This seems to work, but I’m not fond of how “limited” it seems… meaning, it sort of locks you into using just one display group, etc.

I hope to get some time to experiment with this further next week and make it more expandable and better, but I’m curious what you came up with in the meantime…

Brent [import]uid: 200026 topic_id: 35817 reply_id: 144918[/import]

I believe I found a solution, let me know if this is proper Coronaese/Coronese:

First, within linedraw.lua, I create a display group (to hold all objects for linedraw.lua) and attach it to the LD table:

--linedraw.lua--  
  
local LD = {}  
...  
local function startListener()  
 print("starting listener...")  
 Runtime:addEventListener("touch", drawDots)  
---Create display group:  
 LD.linedrawgroup = display.newGroup()  
end  
...  
return LD  

Then…

I pull said group into my level1.lua and localize it, like so! :

--level1.lua  
  
--Import display group from linedraw.lua and localize:  
  
local LDgroup = LD.linedrawgroup  

Bonus:
…and then all I have to do for easy clean up, is put said group into a master group within level1.lua!
[import]uid: 73951 topic_id: 35817 reply_id: 144930[/import]

For reference, here is what I have so far:

--level1.lua  
display.setStatusBar ( display.HiddenStatusBar )  
local LD = require("linedraw")  
local removeAll  
local myGroup  
  
local function start()  
myGroup = display.newGroup()  
LD.startListener( myGroup )  
local button = display.newCircle( 0,0,50)  
button.x = display.contentWidth\*0.5; button.y = display.contentHeight-25  
button:setFillColor(255, 23, 75)  
button:addEventListener("tap", removeAll)  
myGroup:insert( button )  
 end  
function removeAll()   
 LD.endListener()  
 display.remove( myGroup )  
 myGroup = nil  
 timer.performWithDelay(1000,start)  
 return true  
end  
  
--INIT--  
start()  
  
-----------------------------  
--linedraw.lua  
local LD = {}  
  
local putInGroup --up-reference to the dedicated display group  
   
local function erase( event )  
 display.remove( event ) ; event.trans = nil ; event = nil  
end  
   
local function drawDots(args )  
   
 local dot = display.newCircle( putInGroup,0,0,10 ) ; dot:setFillColor(255,255,255)  
 dot.x = math.random(0,320) ; dot.y = math.random(-44,524)  
 dot.trans = transition.to( dot, {alpha=0.5, time=2000, onComplete=erase })  
 dot:toBack()  
 if args == "cancel" then   
 transition.cancel(dot.trans)  
 dot.trans = nil  
 print("tansition cancelled!")  
 end  
  
end  
   
function LD.startListener( myDisplayGroup )  
 Runtime:addEventListener("touch", drawDots)  
 putInGroup = myDisplayGroup  
end  
  
function LD.endListener()  
 drawDots("cancel")  
 Runtime:removeEventListener("touch", drawDots)  
end  
  
return LD  

I’m just trying to accomplish removing the dots created with linedraw.lua when operating from level1.lua.

The red button is a “reset” button.

EDITED: removed globals [import]uid: 73951 topic_id: 35817 reply_id: 143823[/import]