Video icon 64
Learning to code? Skill up faster with our practical video courses. Start your free trial today.
Advertisement

Quick Tip: How to Debug an AS3 Error #1009

by
This post is part of a series called How to Fix Bugs in Flash.
Fixing Bugs in AS3: Introduction
Quick Tip: How to Debug an AS3 Error #1063

One of the more common questions I see on forums and get from colleagues is how to debug Error 1009, also known as the “Null Object Reference Error.” Or, as I call it, the “Annoying Mosquito Error From Hell.” It crops up a lot, and unfortunately the error itself does not contain much information about the source of the error. In this quick tip, we’ll take a look at some steps you can take to track down this mosquito and squash it good.


Introduction

This piece is the first followup to the more general “Fixing Bugs in AS3” tutorial. If you wish to better understand some of the techniques in this tip, you may wish to read that in full first.


Step 1: Understand the Error

It’s too bad that Adobe doesn’t (or can’t) provide more information about the root of this error. First of all, it’s rather obtusely worded (much like all of their errors, but this more so than most):

TypeError: Error #1009: Cannot access a property or method of a null object reference

Let’s try to put this in everyday terms. Error 1009 means that you’ve tried to do something with a variable that you assume has a value, but really does not. Flash doesn’t like that. You wouldn’t like it either; imagine you had a glass that you assumed was full of the tasty beverage of your choice, but really was empty. You grab the glass, expecting a refreshing swig, but you feel the disappointing weight of an empty glass instead. That’s your own personal Error 1009.

In ActionScript, if you do this:

var s:String;
trace(s.toUpperCase());

Flash will bum hard (a technical term for “produce an error”) when you run the code. The variable s may have been declared, but its value is null (we never set the value, just declared the variable), so calling the toUpperCase method on it is troublesome.

To be clear, because s is declared as a String, the compiler takes no issue with the code: there is a variable called s, it’s a String, and toUpperCase is a valid method to call on Strings. The error we get is a run-time error, which means we only get it when we run the SWF. Only when the logic is performed do we now get to see how this turns out.


Step 2: Permit Debugging

As with any run-time error, sometimes it’s pretty easy to tell what’s going on without any extra information. But other times it’s helpful to narrow this down further. At this point, try turning on “Permit Debugging.” When this is enabled, you get errors that also give you line numbers. Alternatively, you may be able to “Debug Movie” by pressing Command-Shift-Return / Control-Shift-Enter.

To do so, see the general debugging tips article, “Fixing Bugs in AS3”

Sometimes this is enough. Knowing the specific line might be all the information you needed. If not, we’ll dig a little deeper in the next step.

Our dear editor, Michael James Williams, encapsulated the point of this step in a limerick, which I’m happy to present to you now with his kind permission:

AS3 error one-oh-oh-nine

Is never a very good sign.

No need for concern,

Hit Ctrl-Shift-Return

And it’ll pinpoint the cause (well, the line).


Step 3: Start Tracing

If you’ve located the offending line but are still unsure what’s going on, pick apart the line. Take every variable in that line and trace them out prior to the error.

Because the error comes when accessing a property or calling a method on a null variable, to cover your bases you should trace any variables and properties that are immediately followed by a dot. For example, take this line of code:

myArray.push(someSprite.stage.align.toLowerCase());

Admittedly, that’s a rather contrived piece of code that I can’t imagine a practical use for, but you should identify four total possible null values that are being accessed with the dot:

  • myArray: we are calling the push method on this variable
  • someSprite: we are accessing the stage property
  • stage: we are accessing the align property
  • align: we are calling the toLowerCase method

So your debugging code might look like this:

trace("myArray: ", myArray);
trace("someSprite: ", someSprite);
trace("someSprite.stage: ", someSprite.stage);
trace("someSprite.stage.align: ", someSprite.stage.align);

Order is important; if someSprite is the null object, but you test for someSprite.stage.align before testing for someSprite, you end up with less definitive results.

Now, common sense also plays into this. In my example, if stage exists, then align will most assuredly have a value; the Stage always has an align setting, even if it’s the default value.

Typically, you’ll see something like the following:

myArray: [...stuff in the array...]
someSprite: [object Sprite]
someSprite.stage: null
Error #1009: ...

Which should clue you in that the stage property is null, and now you can go about fixing it.


Step 4: Finding a Solution

The easiest solution is to wrap up the offending statement in an “if” block, and only run the block if the variable in question is not null. So, assuming that in our previous example, it was in fact stage that was null, we could do something like this:

if (someSprite.stage) {
    myArray.push(someSprite.stage.align.toLowerCase());
}

This test — if (someSprite.stage) — will return true if there is a value (regardless of the value), and false if it’s null. In general this notation works; you can always use if (someSprite.stage != null) if you prefer. Numbers present a slightly different situation, though. If the Number has a value of 0, then technically it has a value, but testing if (someNumberThatEqualsZero) will evaluate to false. For Numbers you can use the isNaN() function to determine if a valid numeric value is stored in a given variable.

At any rate, this technique is a simple way to sidestep the error. If the variable we want to perform an operation on is not set, then don’t do the operation. If there is no tasty beverage in our glass, don’t pick up the glass. Simple enough.

But that approach is only feasible if the logic is optional. If the logic is required, then perhaps you can provide a default value to the questionable variable before the error-ing operation. For example, if myArray has the potential to be null, but it’s imperative that it’s not, we can do this:

if (!myArray) {
    myArray = [];
}
myArray.push(someSprite.stage.align.toLowerCase());

This will first check to see if the array is null. If it is, initialize it to an empty array (an empty array is a valid value. It may be empty, but it’s an array, and not null) before running the contrived line of code. If it’s not null, skip straight to the contrived line of code. In real-life terms, if our glass is empty, then fill it with a tasty beverage before picking it up.

In addition, if myArray is an instance property of the class in which this line of code is running, you can pretty safely ensure a valid value by initializing your properties when the object initializes.

What if the logic is required, but the variable in question is not so readily under our control? For example, what if our contrived line of code is required, but the questionable variable is someSprite.stage? We can’t just set the stage property; that’s controlled internally to DisplayObject and is read-only to us mere mortals. Then you may need to get crafty, and read the next step.


Step 5: Dealing with a null stage

There are probably an infinite number of scenarios where a given variable or property could be null. Obviously, I can’t cover them all in a Quick Tip. There is one specific situation, however, that crops up again and again.

Let’s say you write some code that looks like this:

public class QuickSprite extends Sprite {
    public function QuickSprite() {
        stage.addEventListener(MouseEvent.MOUSE_MOVE, onMove);
    }
    private function onMove(e:MouseEvent):void {
        var color:ColorTransform = new ColorTransform();
        color.color = stage.mouseX / stage.stageWidth * 0xFFFFFF;
        this.transform.colorTransform = color;
    }
}

Another contrived bit of code (which might induce seizures — consider yourself warned), but basically the idea is that you have a Sprite subclass and you set this as the class for a clip on the stage, using the Flash IDE.

However, you decide you want to work with these QuickSprites programmatically. So you try this:

var qs:QuickSprite = new QuickSprite();
addChild(qs);

And you get the accursed Error 1009. Why? Because in the QuickSprite constructor, you access the stage property (inherited from DisplayObject). When the object is created entirely with code, it is not on the stage at the point that that line of code runs, meaning stage is null and you get the error. The QuickSprite gets added the very next line, but it’s not soon enough. If the instance is created by dragging a symbol out of the library and onto the stage, then there’s a little bit of magic at work behind the scenes that ensure that the instance is on the stage (that is, the stage property is set) during the constructor.

So here’s what you do: you test for the existence of a value for stage. Depending on the result, you can either run the set up code right away, or set up a different event listener for when the QuickSprite does get added to the stage. Something like this:

public function QuickSprite() {
    if (stage) {
        init();
    } else {
        this.addEventListener(Event.ADDED_TO_STAGE, init);
    }
}
private function init(e:Event=null) {
    this.removeEventListener(Event.ADDED_TO_STAGE, init);
    stage.addEventListener(MouseEvent.MOUSE_MOVE, onMove);
}

If we move the stage line to a different function, and only call that function when we have a stage, then we’re set. If stage exists from the start, go ahead and run init() right away. If not, we’ll use init() as an event listener function for ADDED_TO_STAGE, at which point we will have a stage value and can run the code. Now we can use the class for either connecting to IDE Sprite or completely programmatically.

This works well in document classes, too. When you run a SWF by itself, the document class has immediate access to stage. If you load that SWF into another SWF, though, the code in the document class’s initialization stack gets executed before the loaded SWF is added to the display. A similar stage-checking trick will allow you to work with the SWF as both a standalone piece and as a SWF loaded into a containing SWF.


That Is All

Thanks for reading this Quick Tip! I hope you are enlightened a bit about how Error 1009 occurs, and how you can debug it. Stay tuned for more Quick Tips on other common errors.

Advertisement