AS3 | Flash | Tips

This isn’t right… MovieClip nested inside Button throwing null object reference error in Flash CS4

A great thing about teaching is that your students approach problems in ways you haven’t done before and run into problems that you never knew existed. This is one such problem in Flash CS4 and a curious one at that.

THE PROBLEM: A Button symbol is placed on the Stage on a frame other than the first frame and given an instance name in the Properties panel. In the Actions panel, ActionScript is added that references the instance name of the button on the same frame that the button instance first appears on. The movie is tested and the following error occurs:

TypeError: Error #1009: Cannot access a property or method of a null object reference.
at MovieClipInsideButton_fla::MainTimeline/frame2()

Normally this error means that a particular instance has not been given an instance name in the Properties panel on the frame where the ActionScript appears. However, nothing looks amiss in the ActionScript or on the Stage. Adding a trace statement, such as trace(myButton); reveals null in the output window, meaning the trace statement has run before the instance name has been set to the button instance on the Stage. Hmm… very perplexing, since you may have other buttons and movieclips that work fine when referenced from ActionScript.

THE SOLUTION: From what I found, one scenario will produce this error. If a MovieClip symbol (instance) appears inside a Button symbol and the button appears on any frame other than the first frame, and the frame where the ActionScript references it is the same frame it first appears on—then this behavior will result.

MC_inside_button

There are a few workarounds:

  1. Retrieve the instance from the display list of its parent. Instead of referencing the Button instance on the stage directly, use getChildByName(.) to retrieve a reference to the instance, this can even be set to instance name at the beginning of your timeline code, like so:
    // myButton is the name of the instance as set in the Properties panel.
    // Retrieved child is cast as a SimpleButton, since this is the 
    // class of the Button symbol
    myButton = SimpleButton(getChildByName("myButton"));
  2. Do not nest a MovieClip inside a Button symbol. A Button nested inside a Button, a MovieClip nested inside a MovieClip, and a Button nested inside a MovieClip work fine.
  3. Place the first occurance of the Button instance on any frame before the frame where ActionScript first references it. This behavior appears to indicate Flash is taking too long to parse over the MovieClip inside a Button and runs the ActionScript on the timeline prematurely. Having the instance appear on a frame prior to the frame the ActionScript appears on ensures the instance is completely present in memory before it is referenced.
  4. Place the instance referencing code inside an enter frame event handler function. To ensure the entire frame has been parsed before any ActionScript code is run, enclose the offending code inside the event handler function of the enter frame event, and only make it run once, like so:
    addEventListener( Event.ENTER_FRAME , ensureRendered );
     
    function ensureRendered( evt:Event ) : void
    {
    	removeEventListener( Event.ENTER_FRAME , ensureRendered );
    	// All instance referencing code appears below this point
    	// In this case, instance is named "myButton" on the Stage
    	myButton.width = 200;
    }

This behavior doesn’t seem right to me and even seems it could be a bug. If anyone has an explanation for this behavior, I would love to hear it. You may download an example FLA here: Download Source

UPDATE September 20, 2009: I added a new workaround, which is probably the most succinct and reliable one yet to use. See Retrieve the instance from the display list of its parent in the list of workarounds.