AS3 Error reporting from event callback - actionscript-3

I have been experimenting with supplying better debugging information when an error happens in asynchronous code in AS3.
As an example of the poor error reporting be default, take the case where I force a null pointer in a Timer callback (github gist), I get the following stacktrace back on the console:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at Function/<anonymous>()[/[path-to-source-file]/TestClass.as:14]
at flash.utils::Timer/_timerDispatch()
at flash.utils::Timer/tick()
This tells me very little about how the timer callback actually links to my code.
The question is: How can I get information about what code created the callback?
I have added one of my solutions below. I'm interested to see if this can be improved.

One possible solution is to pre-create an Error object in the consumer "thread"/"scope"
var errorInConsumerScope:Error = new Error()
var timer:Timer = new Timer(1000, 1)
timer.addEventListener(TimerEvent.TIMER, internalCallback)
timer.start()
function internalCallback(e:TimerEvent):void
{
try
{
// do something that could cause an error
}
catch (e:Error)
{
errorInConsumerScope.message = e.message
throw errorInConsumerScope
}
}
This now gives me the stacktrace back into my calling code:
Error: Error #1009: Cannot access a property or method of a null object reference.
at TestClass()[/[path-to-source-file]/TestClass.as:10]
at Main()[/[path-to-source-file]/Main.as:9]
The complete gist is here

Interesting thing.
The doc to Error.getStackTrace() says:
Returns the call stack for an error as a string at the time of the
error's construction
According to this, the stacktrace works as expected. The error is constructed in your event handler which is called by the timer tick event.
In your second example you create the error to be dispatched in the constructor of the TestClass. So your stacktrace will show the chain up to the TestClass constructor.

You probably ask for a general solution. I would go with unit tests and proper debugging using breakpoints and object inspection. But here another idea:
TestClass:
package {
import flash.events.TimerEvent;
import flash.utils.Timer;
public class TestClass {
public function TestClass(userCallback : Function, fail : Function) {
var timer : Timer = new Timer(1000, 1);
timer.addEventListener(TimerEvent.TIMER, internalCallback);
timer.start();
function internalCallback(e : TimerEvent):void {
try {
var nullProperty : String;
nullProperty.length;
} catch (e:Error) {
fail();
return;
}
userCallback();
}
}
}
}
Main:
package {
import flash.display.Sprite;
public class Main extends Sprite {
public function Main() {
new TestClass(
function() : void { trace('Call me back when your done.'); },
function() : void { throw new Error('Something went wrong.'); }
);
}
}
}
Output:
Exception fault: Error: Something went wrong.
at Function/<anonymous>()[Main.as:8]
at Function/TestClass/$construct/internalCallback()[TestClass.as:16]
at flash.utils::Timer/_timerDispatch()
at flash.utils::Timer/tick()

Related

Variable dispatch is not defined

I'm getting an anoying error while triying to dispatch a custom Event.
What I'm triying is this:
1- Setting a listener in a .as file.
import flash.events.Event;
emisor.addEventListener("accionTerminada", onAccionTerminada)
function onAccionTerminada(evento:Event):void{
trace("Accion Terminada");
}
2- Launching the event in another .as
dispatchEvent(new Event("accionTerminada"));
But I don't know why I'm getting the following error
ReferenceError: Error #1065: Variable dispatchEvent is not defined.
Don't know why its passing dispatchEvent as a variable instead of a function...
Also tried dispatch having the same error.
Thanks
EDIT:
The other .as.
public class CustomPalManager implements IProvideCustomPalList, IManageCustomPal {
[Inject]
public var space:CurrentSpaceCustomPal;
private var _collection:VectorCollection;
public function remove(target:CustomPalVO):void {
var index:int = space.value.content.indexOf(target);
if (index != -1) {
space.value.content.splice(index, 1);
collection.refresh();
//dispatchEvent(new Event("updateAfterDelete"));
} else {
throw new ArgumentError("Impossible to remove wall, it doesn't exist");
}
}
}
}

TRIED ALMOST EVERYTHING: ypeError: Error #1009: Cannot access a property or method of a null object reference

I am having this problem and cant get around it at all
im making a platform game for uni
i have 2 files
flashgame.fla and Coin.as (this is code for the Coin class)
i have code stating that once the player has collected all the coins the frame will change from frame 1 to frame 2.
When i do i receive this message
TypeError: Error #1009: Cannot access a property or method of a null
object reference. at Coin/update() TypeError: Error #1009: Cannot
access a property or method of a null object reference. at
flashgame_fla::MainTimeline/loop()
i have tried Try and Catch and various other things
I think it does this because the Coin.as extends MovieClip so when it goes to the next frame it is still trying to find a coin when nothing is there.
here is the code for Coin.as
package {
import flash.display.MovieClip;
import flash.events.*;
public class Coin extends MovieClip {
var player:MovieClip;
var mainTimeLine = MovieClip(root);
public function Coin() {
this.addEventListener(Event.ENTER_FRAME, update);
}
function update(event:Event):void
{
player=MovieClip(root).player;
if(this.hitTestObject(player))
{
this.removeEventListener(Event.ENTER_FRAME, update);
parent.removeChild(this);
mainTimeLine.coinCount++;
}
}
}
}
i have an array in flashgame.fla that records all coins in the game. when the player hits them they are spliced from the array. could also be causing the problem when going to frame 2
important stuff from flashgame.fla
var coin:Array = new Array();
for (i=0; i<numChildren; i++)
{
if (getChildAt(i) is Coin)
{
coin.push(getChildAt(i).getRect(this));
}
}
splicing coins
for (i=0; i<coin.length; i++)
{
if (player.getRect(this).intersects(coin[i]))
{
coinSnd.play();
coin.splice(i,1);
}
}
Thanks for any help given
if you need anything more from me please ask :)
all g with screenshots
It's most likely because the player cannot be found in the update function in the Coin class. This is because ENTER_FRAME events are run even if the display object is not on the stage, which you often don't want. In this case you try to do a hittest against the player.
To solve this, you can start running update as soon as the Coin is attached to the stage and stop running it as soon as it's removed from the stage.
public function Coin() {
this.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
this.addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
}
function onAddedToStage(event:Event):void {
this.addEventListener(Event.ENTER_FRAME, update);
}
function onRemovedFromStage(event:Event):void {
this.removeEventListener(Event.ENTER_FRAME, update);
}
Which line number is the error occurring on? That should tell you which variable is null.
My guess, based on this part of the error: "TypeError: Error #1009: Cannot access a property or method of a null object reference. at Coin/update()", is that the parent of the coin is null because you've moved to a new keyframe and the instance has been removed from the stage.
That is, I suspect the error is occurring on the line with parent.removeChild(this); - is this correct?
If that's the case then check whether parent is not null before calling removeChild on it.

Loader-Class - SecurityError: Error #2000: No active security context

I try to "catch" this error when I'm loading some images.
The following code is an test-case for my problem to secure that there are no errors in the surrounding code.
import flash.events.SecurityErrorEvent;
import flash.display.Loader;
import flash.net.URLRequest;
loadImage ();
function loadImage (): void {
var _imageLoader = new Loader();
_imageLoader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, imageSecurityErrorEventListener);
var request:URLRequest = new URLRequest("this-image-not-exits.jpg");
_imageLoader.load(request);
}
function imageSecurityErrorEventListener (e:SecurityErrorEvent) {
trace ("This is my own trace for the Security Error");
}
I know that there are lot's of posts and questions in the www and here, but I couldn't find an answer to my problem.
I'm working on an interactiv-movie with many images and movies which are loaded dynamically in the application.
In this snipped I generated the worst case in my application (try to load an image that not exits).
When I run this code I get the trace "SecurityError: Error #2000: No active security context" and not the trace of my the Listener.
Do you have any idea whats going wrong?
That specific security error is thrown rather than dispatched as an ErrorEvent.
It can be detected by using a try...catch block instead:
function loadImage (): void
{
var _imageLoader = new Loader();
_imageLoader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, imageSecurityErrorEventListener);
var request:URLRequest = new URLRequest("this-image-not-exits.jpg");
try
{
_imageLoader.load(request);
}
catch (error:Error)
{
trace("A different error was thrown, not dispatched as an ErrorEvent");
}
}
For a full list of all errors thrown or dispatched as Events, see the Adobe language reference page: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/Loader.html#load()

In flash AS3 How to put single try catch code, in order to catch any errors in whole class?

In Flash AS3 I wanna write the single try catch block in order to catch any errors in whole class.
For example, I have a lot of functions in myClass.as. I don't wanna write in each function try catch blocks in order to catch errors in this function.
Is there any methods to do this?
Thank you!
you can't! there is no such easy way like that even in other language either than AS3 except they use AOP approach to do that.
The best practice is just let you classes bubble the Error (Exception) and let the higher layer catch and process the error.
EDIT - regarding coment
Actually the idea is the natural way.. still you need to manually catch every possible error. i'll give you example. Note that the purpose of the example only for clarity between lower layer and higher layer.
for example you have a class in the mid layer (Your Business Process):
public class MyBussiness {
public function loadImages(){
//for example here is a block of method
//possibly throws exception.
}
public function getLoan(){
//lets assume here too
}
}
in the higer layer (I Assume in your View - MXML) you catch the exception like bellow:
var myBussiness:MyBussiness = new MyBussiness():
try {
myBussiness.loadImages();
//any other sequence process
myBussiness.getLoan();
}
catch(error:Error){
//here you process error
//show it to user or make LOG
}
still it can't do a magic like you expect but it is the best practice. Rember only put try catch only on code that has possibility to throw error because try catch is expensive.
The best way is using try catch:
try{
//your command
} catch(e:Error){
//your command
}
You can catch all not handled errors in your program by using UncaughtErrorEvent class.
So, may be it what you want. There is an example from the docs (you could place addEventListener in the constructor of your main class):
package
{
import flash.display.Sprite;
import flash.events.ErrorEvent;
import flash.events.MouseEvent;
import flash.events.UncaughtErrorEvent;
public class UncaughtErrorEventExample extends Sprite
{
public function UncaughtErrorEventExample()
{
loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, uncaughtErrorHandler);
drawUI();
}
private function uncaughtErrorHandler(event:UncaughtErrorEvent):void
{
if (event.error is Error)
{
var error:Error = event.error as Error;
// do something with the error
}
else if (event.error is ErrorEvent)
{
var errorEvent:ErrorEvent = event.error as ErrorEvent;
// do something with the error
}
else
{
// a non-Error, non-ErrorEvent type was thrown and uncaught
}
}
private function drawUI():void
{
var btn:Sprite = new Sprite();
btn.graphics.clear();
btn.graphics.beginFill(0xFFCC00);
btn.graphics.drawRect(0, 0, 100, 50);
btn.graphics.endFill();
addChild(btn);
btn.addEventListener(MouseEvent.CLICK, clickHandler);
}
private function clickHandler(event:MouseEvent):void
{
throw new Error("Gak!");
}
}
}
See the docs, please.

pass class as parameter, then instantiate from class

I've done this before, but i can't quite remember the syntax.
What i've got (simplified):
function createText(clazz:Class)
{
var font:Font = new clazz(); //throws Instantiation attempted on a non-constructor.
}
I believe this can be done without using getQualifiedClassName, but its been a long time. Any help appreciated.
You are probably passing null to the function.
package
{
import flash.display.Sprite;
public class ClassTest extends Sprite
{
function ClassTest()
{
makeObject(Object);
makeObject(Sprite);
makeObject(null);
}
private function makeObject(type:Class):void
{
trace(typeof type);
var obj:* = new type();
trace(typeof obj);
trace("");
}
}
}
This outputs:
object
object
object
object
object
TypeError: Error #1007: Instantiation attempted on a non-constructor.
at ClassTest/makeObject()
at ClassTest()
how are you passing the class to the function ?
the calling line should have trown an error in the first place if the wanted class wasn't available, this is weird.
can you post the real code ?
here a trick for loading a class compiled in an external swf
var clazz:Class = this.yourLoader.contentLoaderInfo.applicationDomain.getDefinition("yourClassName") as Class;
Turns out I hadn't given the font a class name in CS3. So yes,I was passing null.