GhostWire Studios - Flash/Flex UI Components Development And Consulting Services
Quality User Interface Controls For Flash Application DevelopmentAspireUI Components

Aug 18 2009

[AS3] Avoiding NULL Object Reference Error When Loading Module SWF

Published by at 2:58 am under Flash,Flash AS3,Tips

When building modular Flash applications, a common error that may be encountered is that related to accessing a property or method of the stage property when it is still null. If a display object is not yet added to the display list, its stage property returns null.

An ActionScript error has occurred: “Cannot access a property or method of a null object reference.”

Quite a cryptic message, especially if you test the module SWF standalone and nothing seems wrong, but the error is thrown when you load the module SWF into a host SWF.


Background of the Problem
When a module SWF is loaded into a host SWF, the constructor of the top-level class of the module SWF will be called before the instance itself (Sprite or MovieClip) is added to the display list. In other words, the stage property will still be null when the class is being instantiated and therefore, referencing a property or method of the Stage object (via the stage property) in the constructor of the top-level class will result in a “null object reference” error.

The same occurs, of course, if the constructor does not reference a property or method of the stage directly, but calls another member (function or get/set property) that does so.


Example of the Problem
Let’s take for example we want the application to be notified when the Stage is resized and will therefore attach a listener to the Stage. The following will work if the SWF is run standalone, but will throw the “null object reference” error if it is loaded into a host SWF:

package 
{
	import flash.display.Sprite;
	import flash.events.Event;
 
	public class Module extends Sprite 
	{
		public function Module()
		{
			init();
		}
 
		private function init():void
		{
			stage.addEventListener(Event.RESIZE, on_stageResize);
			// stage is null, cannot access method of null object, error is thrown
		}
 
		private function on_stageResize(evt:Event):void
		{
			// ** actual application code begins **
			trace("stageWidth: " + stage.stageWidth + " stageHeight: " + stage.stageHeight);
		}
	}	
}


Fix for the Problem
To avoid such an error, simply wait until the display object has been added to the Stage before referencing its stage property. You can do this by listening to the Event.ADDED_TO_STAGE event:

package 
{
	import flash.display.Sprite;
	import flash.events.Event;
 
	public class Module extends Sprite 
	{
		public function Module()
		{
			addEventListener(Event.ADDED_TO_STAGE, init);
		}
 
		private function init(evt:Event):void
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			// remove the event listener, because it is possible for the instance
			// to be removed from its container, and re-added to the display list
			// and invoking the event again but we want to call the init method
			// only once per instance of the class
 
			// ** actual application code begins **
			trace(stage); // stage is no longer null
			stage.addEventListener(Event.RESIZE, on_stageResize);
		}
 
		private function on_stageResize(evt:Event):void
		{
			// ** actual application code begins **
			trace("stageWidth: " + stage.stageWidth + " stageHeight: " + stage.stageHeight);
		}
	}	
}


As mentioned above, even if the constructor itself does not reference a property or method of the stage directly, but calls another member (function or get/set property) that does so, or the member calls another member that does so, and so on (you get the idea)… this “null object reference” error will still occur. The referencing may be deeply nested, and therefore, it is probably best to make it a habit to have your top-level class listen for the Event.ADDED_TO_STAGE event before executing other code:

package 
{
	import flash.display.Sprite;
	import flash.events.Event;
 
	public class Module extends Sprite 
	{
		public function Module()
		{
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
 
		private function init(e:Event = null):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
 
			// ** actual application code begins **
			trace(stage); // stage is no longer null
		}
	}	
}


FlashDevelop
If you are using the FlashDevelop IDE, the Main.as class file, written in the way described above, will be created automatically for you when you create a new Project using the “AS3 Project” template. However, when writing module classes and compiling them using the Quick Build command, it will be up to you to remember to write them in the way described above (and it is especially for module SWFs that you need to do this).


Reminder:
A Flash application has only one Stage object – display objects in both the host SWF and in any loaded SWF(s) reference the same Stage. Do not confuse stage with the root property.

pixelstats trackingpixel
Share or Bookmark This Post:
  • StumbleUpon
  • email
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Live
  • Yahoo! Buzz
  • Netvibes
  • NewsVine
  • Reddit
  • Slashdot
  • Technorati
  • BlinkList
  • Mixx
  • Diigo
  • Faves
  • Suggest to Techmeme via Twitter
  • Twitter

Other Posts You Might Enjoy:

       

10 responses so far

10 Responses to “[AS3] Avoiding NULL Object Reference Error When Loading Module SWF”

  1. Alex Angelicoon 27 Oct 2009 at 8:51 pm

    Dear Sunny, THANK YOU VERY MUCH!!!!
    I didn’t had a clue how to solve this issue, and your solution is so simple and clear!!!

  2. MicLon 30 Nov 2009 at 3:30 pm

    Thanks for this post. Cleared things up for me :)

  3. Murdochon 21 Dec 2009 at 3:24 am

    This is exactly what I was looking for. It was doing my head in. Another fix is putting all code on the 2nd frame of the loaded SWF but this approach is much more elegant and correct. My Flash IDE approach is below (all code on first frame of loaded SWF):

    this.addEventListener(Event.ADDED_TO_STAGE, init, false, 0, true )
    function init(event:Event):void {
    trace(MovieClip(this.parent.parent));
    // calls to main timeline will now work
    }

  4. Rasmuson 18 Mar 2010 at 4:05 pm

    thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you!! This was killing me – I was thinking about a career change!

  5. bmkhoaon 16 Sep 2010 at 8:40 am

    Excuse me for my stupid question! Why the error does not occur if the flash run standalone?

    Even in standalone mode, in constructor context, the flash object still not fully created, so it is not added to stage, still get null reference to stage. Right?

  6. sunnyon 16 Sep 2010 at 9:44 am

    run time errors like this are not shown in release versions of the flash player (but it does not mean the error does not occur). debug standalone will still show the error.

  7. bmkhoaon 17 Sep 2010 at 6:40 am

    If the flash is still unchanged, it access stage on constructor. Is there a way to workaround? I am stuck in this error, because I can not have all the third-party flashes recompiled!

  8. sunnyon 18 Sep 2010 at 2:51 pm

    @bmkhoa, I don’t know of any workaround, and I actually don’t think you can workaround this. I mean theoretically a workaround is impossible since the stage object is going to be NULL in the constructor and if your module SWFs are doing stuff with the stage object in the constructor, I guess you are out of luck if you cannot change the code in the module SWFs.

    Sorry I misunderstood your earlier question. Yes, it is strange that running a SWF on its own and loading it into a host SWF yields different results. However, think of it this way – when you run a SWF directly on its own, the top level display object is the top level class (so stage is not NULL) whereas loading a SWF as a module is a two step process (instantiating the class as a display object, then adding it as the child of the Loader object).

    I wished Adobe would actually design the player API such that stage is always defined (it should, since there is only ever going to be just one stage). Stage really should be a globally accessible object that always point to the top level display object, but unfortunately it isn’t.

  9. bmkhoaon 20 Sep 2010 at 2:24 am

    Thanks very much sunny. It’s really out of luck.
    I also wish Adobe would let stage accessible from all, or unaccessible from all until the flash is fully created and added to stage.

  10. bochelordon 29 Oct 2010 at 1:59 pm

    Thanks a lot for a clear and solving explanation!

Comments RSS

Leave a Reply

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word