hi Craig,
to answer your question, using a single function to remove your buttons is fine. as a good rule of thumb, objects should be created and destroyed at the same “context level” in an app. you have done this in your code example by creating and destroying the buttons at the same level, ie, in main.lua at the App level, so this is good.
however, to promote better programming practices, this function shouldn’t be global. currently destroyButtons() is called from within a button object thus must be global. that breaks OO because you have given your buttons an “awareness” of their parent or surroundings which they shouldn’t have. in OO, the button class should only know about its world and nothing else.
so what we need to do is just improve upon how the destroyButtons() is called.
enter events and listeners
probably the biggest benefit of events is to “decouple” different parts of an application. meaning we can still have communication, but if no one is listening then it doesn’t matter because nothing is going to break.
in your case we can create a custom event to achieve the same effect as the global method call, improve encapsulation within the app, and increase the re-usability of your button objects. win, win, win !
note that only Corona objects can be used to broadcast events. so the challenge in setting this up with your button class is that the Corona object (the newRect) isn’t at the top level of the button object, but rather located at the property ‘myRectangle’. so you have to take this into consideration.
here is your code re-worked. i have slightly moved around some of the code and added comments.
[lua]
– main.lua
local buttons = require(“button”) – require button class
local allButtons = {} – table to hold all the buttons
– this function isn’t a bad idea, but don’t think of it as global
– in fact, let’s make it local to force correct programming
– we need to pre-declare this because of removeEventListener()
local destroyButtons
destroyButtons = function()
print( “got button limit event, destroy all buttons” )
for i = #allButtons, 1, -1 do
local button = allButtons[#allButtons]
– must use the Corona object !!
button.myRectangle:removeEventListener( ‘button_limit_event’, destroyButtons )
button:kill()
allButtons[#allButtons] = nil
end
allButtons = nil
end
– this function to explicitly “show” that there is balance in the app.
– ie, create and destroy now have equal counterparts at this level
local createButtons = function()
for t = 1, 3 do --loops to create buttons
for i = 1, 3 do
local button = buttons.new(i * 55, t * 55) --create button
allButtons[#allButtons + 1] = button
– initialize, add the button listener
button:init()
– listen for button limit, must be on Corona object !
button.myRectangle:addEventListener( ‘button_limit_event’, destroyButtons )
end
end
end
createButtons()
[/lua]
[lua]
– button.lua
local button = {}
local button_mt = { __index = button }
local function myRectListener (event, self) – button listener
self.counter = self.counter + 1
self.myRectangle.strokeWidth = self.myRectangle.strokeWidth + 1 – do something with the counter
print(self.counter)
– difference here is that we’re creating a custom event
– to send out when our limit is reached and NOT calling
– the destroyButton() function directly.
if self.counter == 4 then
print (“Our limit has been reached, tell someone”)
– create our custom event
local e = {
name=“button_limit_event”
}
self.myRectangle:dispatchEvent( e )
end
end
function button.new(xloc,yloc)
local button ={}
button.myRectangle = display.newRect(xloc, yloc, 50, 50)
button.myRectangle.strokeWidth = 1
button.myRectangle:setFillColor(140, 140, 140)
button.myRectangle:setStrokeColor(180, 180, 180)
button.counter = 0 – counter to store how many times the button has been pressed
return setmetatable( button, button_mt )
end
function button:init()
self.myRectangle:addEventListener(“tap”,function(event) myRectListener(event,self) end) – add a lister to button
end
function button:kill()
self.myRectangle:removeEventListener(“tap”,function(event) myRectListener(event,self) end) – remove the listener
self.myRectangle:removeSelf()
self.myRectangle = nil
end
return button
[/lua]
note that i didn’t call the custom event “destroy_buttons”, because in a way that also implies that the button class knows what is supposed to happen when it sends the event. the issue is that some other app could re-use this button class but want to interpret the action of the event differently, ie, NOT delete the buttons. so, events should only state the facts of what happened.
a concrete example of this is the “tap” event on a Corona object. the event isn’t called “play_sound” because that’s just an action that the higher-level app will perform once it receives the event. the base event is the button saying “hey, someone just tapped me”. that’s it. playing a sound is one action on the event. another app could change the color of the background, or get JSON data from a server.
this is a small detail, but i think helpful when architecting software, especially if you are others are supposed to re-use parts of the code.
cheers,
dmc
ps, the removeEventListener() in your button class won’t actually work. you should read this thread to find out why.
https://developer.coronalabs.com/forum/2013/01/26/advanced-oop-removeeventlistener-question
[import]uid: 74908 topic_id: 36309 reply_id: 144452[/import]