Set event.target to null - actionscript-3

I want to nullify the event.target for garbage collection as the moveclip is no longer needed. What I have roughly is this:
mc.addEventListener(MouseEvent.CLICK, destroy);
public function destroy(event:MouseEvent):void {
event.target.parent.removeChild(event.target);
event.target.removeEventListener(MouseEvent.CLICK, destroyShape);
event.target = null; //THIS IS WHAT I WANT TO ACHIEVE
}
I'm sure this is relatively simple but I'm not sure how to do it.
thanks

You can't change MouseEvent.target value. It's a read only property. If your MovieClip doesn't exist (removeChild) and you removed event handler
mc.removeEventListener(MouseEvent.CLICK, destroy);
then the garbage collector automatically will remove it.

What you are trying to achieve (if it was even possible) would achieve nothing in term of Garbage Collection.
Unless redispatched the event will be garbage collected as soon as the method is done running. All properties of the event will also be discarded. This garbage collection of the event itself and its properties will have absolutely NO EFFECT on the object they point to in term of Garbage collection.
In the scope at which the event was dispatched in the first place the object will continue to exist after the event itself has been discarded. That is at that scope that the object reference must be nullified, not at the event listener scope where it will have no effect since the object still exists at the dispatching scope.
The solution accepted also does nothing. It is as relevant as applying a bandage to a wooden leg. Any local variable in function/method qualify for GC immediately after the method runs. Nullifying those variables has no effect whatsoever and does not constitute a valid answer to any problem and certainly not a GC problem. That those variables are GC does also not constitute a guaranty that the object they point to will be GC.
This is a case where a question about an inexistent and misunderstood problem is asked and answered by posting a false and irrelevant solution.
Case in point: Only a DisplayObject currently in a display list and attached to the stage has the ability to be the target of a MouseEvent. It is simply impossible for that object to become available for garbage collection before it is removed from the display list it belongs to. For those reasons that object cannot qualify for GC at the time the MouseEvent listener runs since that object still has at least one strong reference because it is attached to a display list. This is the proof that what the PO asks is misguided and any code examples are misguided as well since they cannot qualify the object for GC at that point in time.

As #subdan states, the target property of any Event is a readonly property.
You can still null your movie clip but not like in your sample.
mc.addEventListener(MouseEvent.CLICK, destroy);
public function destroy(event:MouseEvent):void
{
var myMC:MovieClip = event.target as MovieClip;
if( myMC )
{
myMC.removeEventListener(MouseEvent.CLICK, destroyShape);
myMC.parent.removeChild(myMC);
myMC = null; //THIS IS WHAT I WANT TO ACHIEVE
}
}

Related

Using retain and release for Objects

Are there any general guide lines for using retain and release for objects in cocos2d-X ? When creating objects in a function, is it true that the functions memory is cleaned up the second the function returns. When a object is created, calling the retain function of the object, will retain object beyond the function return ?
Kind Regards
Generally in c++ you have this behaviour:
void foo() {
Object a;
Object *pA = new Object();
(…)
}
This would result in a being destroyed automatically at function end, as it was allocated on stack. The *pA would not get destroyed, as it was allocated on the heap (thus, you only loose the reference to it, but the object itself still lives).
Cocos implements a thing called "Automatic Reference Counting" : each CCObject has a reference counter and two methods retain() and release(). The way this works is, that every time you create an object, it gets registered in cocos structers (CCPoolManager). Then with every frame (between them being drawn) there is a maintenance loop which checks the reference counter of all objects : if it is 0 this means (to cocos) that no other objects reference it, so it is safe to delete it. The retain count of an object is automatically incresead when you use this object as an argument for an addChild function.
Example :
void cocosFoo() {
CCSprite *a = CCSprite::create(…);
CCSprite *b = CCSprite::create(…);
this->addChild(b);
}
What happens here is this :
Two CCSprites are created, cocos knows about them.
The b sprite is added to this object (say a CCLayer)
The function ends, no objects are destroyed (both of them being on heap).
Somewhere between this and next frame, the maintanance gets run. Cocos chcecks both sprites and sees that a has reference count == 0, so it deletes it.
This system is quite good, as you don't need to worry about memory management. If you want to create a CCSprite (for example), but not add it as a child yet, you can call retain() on it, which will raise its reference counter, saving it from automatic deletion. But then you'd have to remember about calling release() on it (for example, when adding it as a child).
The general things you have to remeber about are :
Each call to retain() by you needs to be paired with release().
You generally shouldn't delete CCObjects yourself. If you feel that you need to, there is a conveniece macro : CC_SAFE_DELETE(object)
So to answer your questions in short :
Are there any general guide lines for using retain and release for objects in cocos2d-X ?
Yes, you should generally not need to do it.
When creating objects in a function, is it true that the functions memory is cleaned up the second the function returns.
Answer to this is the whole text above.
When a object is created, calling the retain function of the object, will retain object beyond the function return ?
Yes, as will adding it as a child to another (retained in any way) object.
Here is the thing,
cocos2dx has an autorelease pool which drains the objects which have retain count=0 which is a variable to keep in check the scope of the cocos2dx object.
Now when you create new object using the create method it is already added to the autorelease pool and you don't need to release it or delete it anywhere , its like garbage collector in java, takes care of garbage objects behind your back.
But when you create new object using 'new' you definitely need to release it in its destructor or after its use is over.
Second thing,
when your object is added to the autorelease pool but you need it somewhere else you could just retain it , this increments its retain count by one and then you have to manually release it after its use is over.
Third Thing,
Whenever you add child your object it is retained automatically but you don't need to release it rather you remove it from the parent.

Property null is read-only

It might not be the null property, but here's what's up:
Let's say I have this code -
1. someclipthatsinanarray[i].addEventListener(Event.ENTER_FRAME, arrayframe);
2. function arrayframe(e:Event):void
3. {
4. e.currentTarget.removeEventListener(Event.ENTER_FRAME, arrayframe);
5. e.currentTarget.parent.removeChild(e.currentTarget);
6. e.currentTarget = null;
7. }
- and pay attention to line six. I run this in the debugger and get this error:
Error 1119: Line 6, arrayframe: Property is read - only.
What is read only? If null is read - only, then why?
currentTarget is a property of the Event. It is read only and you cannot modify that property.
Here is what I think you desire to do :
someclipthatsinanarray[i].addEventListener(Event.ENTER_FRAME, arrayframe);
// event handler
function arrayframe(e:Event):void
{
var clip:MovieClip = e.currentTarget as MovieClip;
clip.removeEventListener(Event.ENTER_FRAME, arrayframe);
clip.parent.removeChild(clip);
clip = null;
}
As mentioned in the comments this line is not doing what you likely believe it is :
clip = null;
clip was just a local reference to that MovieClip, just the same as the element in the array is just a reference to the MovieClip. So setting clip to null, is not deleting the MovieClip, it's merely just nulling out our reference, which really is not even needed since it's a local variable and it's scope ends upon completion of the handler.
An object is only truly marked for garbage collection once there are no references to the object remaining.
Also important to note that being on the Display List of another object is considered a reference.
e.currentTarget is a property of your event. It is read-only because an event should not be modified after having been dispatched.
Don't worry though, as soon as all the functions listening to this particular event are finished executing their code, the reference to your clip stored in the event will be garbage collected.

Want to clear some doubts regarding Garbage Collection ( AS3.0)

package
{
public class SomeClass
{
public var myBtn:Button ;
public function SomeClass()
{
myBtn.addEventListener( MouseEvent.CLICK, clickFunction) ;
}
function clickFunction(e:Event){
}
}
}
Main Class:
var someClass:SomeClass = new SomeClass(); // step 1
addChild(someClass); // step 2
removeChild(someClass); // step 3
someClass = null // step 4
In the above, I want to completely destroy the someClass instance, so in step 4 it's been assigned null value.
Q1) Is step 4 ( assignment to null ) right way to destroy the instances ?
Q2) I referred : http://gskinner.com/blog/archives/2006/06/as3_resource_ma.html using delete keyword for objects. But i don't think delete keyword can be used for class instances ? How to use it in this case then ?
Q3) What happens to myBtn eventListener in SomeClass. Should i add a removeEventListener manually, before destroying instances of SomeClass. Or would it get destroyed automatically ?
Thanks
1/ Yes. (I assume the someClass variable is an instance variable)
2/ delete does not only remove the value of a variable, but even the variable definition. Since classes in AS3 are sealed in general, it won't work. I.e. delete should only be used on dynamically created members. Mainly "keys" of Object or Dictionary instances. But obviously you can remove the member definition of any class marked as dynamic using delete.
3/ Yes, always remove event listeners manually. You can create weakly referenced event listeners when registering the handler as a listener, but it's best to always make sure event listeners are removed manually, it's more readable, clear and fail-safe.
I tend to have a destroy method in all my classes, which can be called by the instance owner when it's cleaning up its references to a certain instance. This destroy method will unregister all event listeners, nullify instance members and do all kinds of cleanup.
The SomeClass instance you created will get garbage-collected after there are no longer any references to it. By setting your variable to null, it removes that reference, and the SomeClass instance will get garbage-collected as long as there are no more references to it.
In the code above, you do not need to remove the event listener. When a SomeClass instance is collected, all of its member variables will be collected (unless they're referenced elsewhere). Because the event listener has been added to the button, it will be collected when the button is collected.
Something to note, however: if instead of myBtn.addEventListener you had used stage.addEventListener, the stage would retain a reference to your callback function and you could end up with a memory leak. Always remove event listeners that are assigned to objects that will still be around after you care about the listener.
Creynder's advice is good: remove event listeners as a matter of habit. It's only really necessary, however, when an event listener's dispatcher is going to hang around but you don't want the callback to stay in memory.

How much information should one pass through events?

Say, I have a datagrid with checkboxes, and each time a checkbox is marked I store the object in the data property of flex ResultEvent
public class MyItemRenderer extends ItemRenderer{
public static var CLICK:String = "CheckBoxClick";
protected function itemRendererClickListener(data:Object):void{
dispatchEvent(new ResultEvent(MyItemRenderer.CLICK, data))
}
}
I handle the result here.
protected function checkbox_clicked(event:ResultEvent):void{
//Here I do everything I want with the data.
Alert.show(event.result.toString());
}
This is what I've been using for months, but I never wondererd if this was a bad practice.
Or let alone bad practice, what is the optimal way to do this?
it's not really 'bad'. But it does create an additional reference to an object that can potentially keep that object in memory longer (or indefinitely if not managed well).
Generally speaking, you should only store data related to the event itself in the event instance. You can use the event.target and event.currentTarget properties to reference back to the object that dispatched the event and get data that way.
In your case, your event is a check box state change. The event itself (being checked) doesn't need any data associated with it besides the item being checked (which you can get with 'target' or 'currentTarget'). So it would be more appropriate in my opinion to do the following:
Alert.show(MyItemRenderer(event.currentTarget).data.toString());
This keeps your events more reusable
Best practice for Events with data is to use a custom event (see http://cookbooks.adobe.com/post_AS3__Creating_and_dispatching_Custom_Events-17609.html) for explanation
btw, another 'best practice' is to avoid the generic Object class in your code - instead, create a value object class

Removing all references to an object removes event listeners inside that object?

When I have an object, removing all references to it is enough to sign it up for the garbage collector, atleast that's what I heard. Eg.:
removeChild(object);
object = null;
I'm still a bit confused though, because does this mean that the event listeners made inside this object's instance are also automatically removed? Or is there anything I need to do?
Ah, you've hit on the crux of memory management in managed code: if you're an object, and you have a reference to another object (even if it's only in the form of an event listener), then you are at least one reason that object won't be removed from memory during a GC.
For display objects, and in my experience pretty much anytime you want to subscribe to an event dispatcher but not be responsible for that dispatcher's remaining in memory, you should add your event listener with the weak reference option:
myPublisher.addEventListener("myEvent", myHandlerFunction, false, 0, true);
In just about every situation I encounter these days, "false, 0, true" (where true means "use weak reference," and which translates loosely as "add this listener, but don't make it a reason for the dispatcher not to get cleared from memory" -- see the docs for more information) is the proper way to add event listeners. Very few textbooks or documentation snippets illustrate this approach for some reason, which is unfortunate, because it makes for a much more intuitive memory-management experience. I'd suggest using it as the rule rather than the exception.
Hope it helps!
an important thing you should consider is that if an object O has eventhandlers, i.e. methods that were added as eventhandlers to E, then this also count as a reference ... unless you add the handler with weakreference ...
also if you have a closure, whose outer scope contains a reference to O, then this is a reference ...
you do not need to remove all references to O, to sign it up for GC either ... the GC also removes circular references ... it removes all "islands" in memory, if you will ... only "peninsulae" connected of the "continent" of builtin objects, i.e. Timers, the display list, I/O layer etc. are not collected ...
the last paragraph of another post of mine deals with this topic a little ...
so yeah, basically, if O gets GCd, then any event handlers get GCd, unless there is another reference to them ... etc.
hope that helped .. :)
greetz
back2dos