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.
Related
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
}
}
Hello I was wandering if someone could help, I keep getting this error spat back at me when I try to launch something in as3. Do I need to import something? Apologies, I originally learned AS2 and I'm now slowly learning AS3.
baby steps.
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at draganddropframe1_resetter2_0_fla::MainTimeline/frame3()
at flash.display::Sprite/constructChildren()
at flash.display::Sprite()
at flash.display::MovieClip()
this.window_mc.visible = true;
this.windwo_mc.offwindow.addEventListener(MouseEvent.CLICK, shutwin);
function shutwin(event:MouseEvent):void
{
this.window_mc.visible = false;
}
UPDATES -----------
A method that appears to have worked around it by changing the direct path to 'this'. Clicked inside the movieclip, added a layer called actions and inserted this script that referenced the movieClip I wanted to hide when clicked.
this.addEventListener(MouseEvent.CLICK, fl_ClickToHide);
function fl_ClickToHide(event:MouseEvent):void
{
this.visible = false;
}
The error you are getting means an object, (moveiclip, variable, etc ) doesn't exist.
Go to your publish settings, and check the box that says "permit debugging". Then when you get that error in your output window it will also display the exact line number the error occurred on. That line will probably tell you what object is null.
It looks like you have a typographical error in your second line. This line
this.windwo_mc.offwindow.addEventListener(MouseEvent.CLICK, shutwin);
should be
this.window_mc.offwindow.addEventListener(MouseEvent.CLICK, shutwin);
You've interchanged w and o.
Otherwise, I would suggest doing Ribs's answer.
UPDATES ----------- "from me "
A method that appears to have worked around it by changing the direct path to 'this'. Clicked inside the movieclip, added a layer called actions, and inserted this script that referenced the movieClip I wanted to hide when clicked.
this.addEventListener(MouseEvent.CLICK, fl_ClickToHide);
function fl_ClickToHide(event:MouseEvent):void
{
this.visible = false;
}
Place this script inside the Movie.
I'm a beginner of ActionScript 3. Recently I'm trying to use addEventListener to invoke function. I found that there are some examples add a removeEventListener when they invoke functions, such as:
public function Away3DMultiMarkerDemo()
{
addEventListener(Event.INIT, initIN2AR);
super();
}
private function initIN2AR(e:Event = null):void
{
removeEventListener(Event.INIT, initIN2AR);
in2arLib.init( workW, workH, maxPoints, maxReferences, 100, stage );
in2arLib.setupIndexing(12, 10, true);
in2arLib.setUseLSHDictionary(true);
in2arLib.addReferenceObject( ByteArray( new DefinitionaData0 ) );
in2arLib.addReferenceObject( ByteArray( new DefinitionaData1 ) );
in2arLib.setMaxReferencesPerFrame(2);
in2arLib.setMatchThreshold(40);
intrinsic = in2arLib.getIntrinsicParams();
initCamera();
initAway3D();
initText();
initListeners();
}
My question is that do I need to set a removeEventListener each time when I called addEventListener? I did some research that the purpose of adding the removeEventListener is to release memory, otherwise program will keep listen events.
It is good practice to remove your listeners when you no longer need them. But that is a call you must make in each situation.
Adding an event listener by default will hang onto a reference of the thing it is added to. So if you add a listener to a movieclip, and delete that movieclip, it will not be garbage collected because the event listener still has a reference to it. For this reason it is good to remove any listeners on an object as part of your deletion process. Of course you can also use the "weak reference" argument in the addEventListener method, so the listener will not keep the garbage collector from destroying the object.
In the case of the Event.INIT event in your example; That should only ever fire once, so the event handler is the perfect place to make sure you remove the listener.
No. You only have to do this if you want the event to execute only once. You also call it when you no longer need the listener, so that it doesn't waste memory.
If you call it as the very first statement in the function that is called when the event is fired, it will ensure that the listener is only called once.
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.
I am extremely frustrated. I'm following a tutorial and mimicing it on my own. I have been able to sort out most of the errors so far but this one has me stumped. I have tried replacing all of the class files with the tutorial specimen ones but i still get the error.
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at com.senocular.utils::KeyObject/construct()
at com.senocular.utils::KeyObject()
at com.asgamer.basics1::Ship()
at com.asgamer.basics1::Engine()
Now, not really understanding the error properly I paste dumped the files online for you to look at.
Ship class: textbin.com/78z35
Engine class: textbin.com/32b24
KeyObject class: textbin.com/p2725
As the error still occured when using the specimen class files I really have no idea where to begin. I will gladly try out any suggestions.
Tip: If you allow debugging, the exception will tell you the exact line in the source code where the Error is being thrown. Assuming you're using the Flash IDE, go to publish settings and in the Flash tab check "Permit debugging". This will makes thing much easier for you.
Anyway, you have an error message. If you read it carefully, you can narrow down where the problem is. I don't know if you are a programmer or you have any interest in being one; if you're not, this answer will hopefully solve this particular problem. Anyway, if you don't mind the rambling, let me tell you that if you're interested in becoming a better programmer, paying attention to errors and learning how to debug / troubleshoot problems is one of the most important abilities you need to develop (if not the most important one); so maybe this will give you a few hints you can use to solve other problems as well.
The message says:
Cannot access a property or method of
a null object reference.
This means, at some point, you did something like this:
someobject.someMethod();
or
someobject.someProperty = "foo";
And someobject happened to be null. You can't call methods or access properties of null.
Ok, so now you know, somewhere, a variable had null as its value. Notice that the fact that you define a variable of property doesn't mean it actually holds an object.
This just says that a variable called mySprite can hold an object of the type Sprite:
var mySprite:Sprite;
But until at some point you create a Sprite and assign it to mySprite, the value held by mySprite will be null. If you do:
mySprite.x = 0;
Before initializing mySprite (i.e. before assigning a Sprite to it), you will have this same Null Reference error.
This error message also offers some helpul context, which you can use to your advantage (in them old days... errors in Flash were silent; when things didn't work, you had to manually trace down the problem).
Ok, let's break this error message down:
at com.senocular.utils::KeyObject/construct()
at com.senocular.utils::KeyObject()
at com.asgamer.basics1::Ship()
at com.asgamer.basics1::Engine()
What you have above is called a stack trace. It basically tells you where the code blew up, and also gives you some context: how did you get there.
The first line tells where the error actually occurred. That is, the construct method in the KeyObject object. That method was called from the KeyObject constructor, which was in turn called from the Ship constructor, which was in turn called from the Engine constructor.
Now, let's analyze how you got there, following the stack trace, bottom-up:
Code in Engine constructor:
ourShip = new Ship(stage);
This creates a new Ship object. It passes a reference to the stage to the Ship constructor method.
Code in Ship constructor:
this.stageRef = stageRef;
key = new KeyObject(stageRef);
It grabs the ref passed in the previous step. It stores it and creates a new KeyObject object. The KeyObject constructor is passed a reference to the stage (which is the same ref that was passed from Engine to Ship).
Code in KeyObject constructor:
KeyObject.stage = stage;
keysDown = new Object();
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);
stage.addEventListener(KeyboardEvent.KEY_UP, keyReleased);
Now we got to the point where the error message told you the problem was. So, somewhere, you are using a variable that holds null and trying to access one of its methods or properties.
This KeyObject stores the reference to stage it was passed in a static variable and creates a new Object object. So far, no problems. KeyObject cannot be null (it's a reference to a Class). The second line itself cannot have this null problem either. So, if this is all the code in that method, the problem has to be either in the third or the fourth line. Both access the stage reference you passed and try to call a method (addEventListener) on it. So if one fails, the other will fail as well. Then, the third line: that's where the problem has to be.
So, at that point stage is null. As said previously, you can't call a method on null, and that's what the error is telling you.
Now, if you get back to the first method call, you can see this is the origin of the problem:
ourShip = new Ship(stage);
You can be pretty sure that, at this point, stage was null. Add that to the fact that Engine extends MovieClip (which is in turn a DisplayObject), and to the fact that any DisplayObject has a reference to the stage object only while it's added to the display list. The conclusion: an instance of Engine was not attached to the display list when its constructor was ran.
A way to fix this (there might be others) could be moving the code in the Engine constructor to a separate function that will be executed only if / when the Engine object has a valid reference to the stage object.
public function Engine() : void {
if(stage) {
initialize();
} else {
addEventListener(Event.ADDED_TO_STAGE,initialize);
}
}
private function initialize(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE,initialize);
// here goes the code that's currently in Engine constructor
}
Hope this helps.
I have a feeling your stage property is null.
You have have to test this yourself with a trace of the stage object.
In the first line in the constructor of you Engine class, add:
trace(stage);
Add that just above this line:
ourShip = new Ship(stage);
If it traces "null" then that is your problem.