I have been creating a code base for a Screen Manager system that I am using for an iOS app I am building in AS3. I wanted to create a dynamic way to reference and instantiate classes that represent each of the Screens in the app so I can reuse this for other applications in the future and to make it a lot less code intensive.

I setup a series of static variables that held string names to represent each of the Screens in the application. Then when I want to create the screen and add it to the stage I use the getDefinitionByName() method and pass the string name of the class.

In theory, this all made sense and should have worked however I ran into this error that I had never seen before: *(note: StartScreen is the name of the class I was wanting to create an instance of)

ReferenceError: Error #1065: Variable StartScreen is not defined.

I have seen a lot of errors in the 7 years I have been working with Flash and AS3 and there have only been a few where I had absolutely no idea what was causing it. This was one of them.

My first thought was “Of course it’s not defined, there is no variable by that name in my program at all!”, followed quickly by “I hate AS3”. So having no idea I turned to the almighty Google for answers.

I found a few blog posts here and there but there really wasn’t a whole lot of help available. I was able to piece together the fix and thought that someone else may need it so here it is.

Basically it breaks down to 2 ways of using the method. I have always used it when there was an item in my Library with a linkage ID I could pass.

When we do it that way it works:

var _dynamicClass:Class = getDefinitionByName("linkage_name") as Class;
var _instance = new _dynamicClass();

The other way ( and the way I was doing it in this case ) is to reference a Class file. This is where the strangeness begins.

Lets say that you have a class called StartScreen and for the sake of simplicity it is in the default package of your application. So if we call the code the same way …

var _screen:Class = getDefinitionByName("StartScreen") as Class;
var _instance = new _screen();

we should get an instance of the StartScreen class correct? Nope, we get the #1065 error. In order to get this to work we need to simply state the classname before we call it.

StartScreen
var _screen:Class = getDefinitionByName("StartScreen") as Class;
var _instance = new _screen();

The above code actually works. I have tested it with the only difference being I pass a variable holding the name of the Class instead of the string literal as above.

Here is an even stranger gotcha to be aware of. The #1065 error says that the variable is not defined so logically we may try something like:

var StartScreen
var _screen:Class = getDefinitionByName("StartScreen") as Class;
var _instance = new _screen();

This will not work – the same error fires.

 

Another gotcha is when the class you are referencing is in a package. Then you have to access it via it’s package. To reuse my StartScreen example, lets pretend that all my screens are sitting in a screens package. To access the class we need to prepend the class package to the class name – the same as though you were doing an import:

StartScreen
var _screen:Class = getDefinitionByName("screens.StartScreen") as Class;
var _instance = new _screen();

I don’t really have any idea why this work the way it does and I can’t seem to find any explanations in the documentation but this is the way I got it to work for me. If anyone has any suggestions, explanations or knows a better way – I’d love to know about it.

Comments

8 responses to “getDefinitionByName”

  1. Andrew Riddell Avatar

    Thanks!

    I have been using getDefinitionByName to make an instance of a class that is defined in a package – very much like your getDefinitionByName(“screens.StartScreen”) example, and it has been workeding just fine.

    Then suddenly it just stopped working, for no reason that I could find.

    After some hair-tearing, I found your article here.

    Then, I realised that, by chance, I had always been declaring a variable of the type that I was instantiating before I made the call to getDefinitionByName(). But, I had rearranged code, so that variable was no longer being declared before the call to getDefinitionByName().

    By re-instating a decalraration of a dummy vraible of this type, the call to getDefinitionByName() has started being successful again.

    So, I am very grateful for your help.

    Methinks this is a bit of a bug in AS3 (well… at least an “unexpected limitation”).

    1. Ryan Avatar

      @Andrew

      Glad to help! I know that this one has gotten me a few times. Source order can definitely come into play depending on how the application is put together.

      I have gotten into the habit of declaring the variables inside the method that actually makes the GetDefinitionByName() call which would eliminate the issue of where the variables are declared.

      As to whether it’s a bug – I would have to agree. There is no mention of this gotcha (that I can find anyway) in the documentation and as you know it seems to be a bit of voodoo as to why things work the way they do.

      Thanks for the comment and I’d love to see what the finished product is!

      Ryan

  2. Erik Avatar
    Erik

    Hello.

    This happens because the flash compiler does not compile classes into the SWF that it doesn’t think are being used. This is a space and time saving measure. It does not anticipate that you will try to retrieve the non-referenced classes via a getDefinitionByName call, however. So you need to reference the class somewhere in the application, anywhere in the application, which is being compiled.

    I’ve found the cleanest solution to this is to make a class, say called IterativeClasses, and make a reference to any class which might only be instantiated after a getDefinitionByName call. Then make a reference to this inside your main document class. So for example, my IterableClasses class:

    package ws.wild
    {
    import ws.wild.display.modules.CalendarDisplay;
    import ws.wild.display.modules.CollectionsDisplay;
    import ws.wild.display.modules.ContainerDisplay;
    import ws.wild.display.modules.HomeDisplay;
    import ws.wild.display.modules.MapDisplay;
    import ws.wild.display.modules.MenuDisplay;
    import ws.wild.display.modules.SettingDisplay;
    import ws.wild.display.modules.StripDisplay;
    import ws.wild.display.modules.WorldDisplay;

    public class IterableClasses
    {
    public function IterableClasses()
    {
    HomeDisplay;
    WorldDisplay;
    ContainerDisplay;
    SettingDisplay;
    StripDisplay;
    MapDisplay;
    MenuDisplay;
    CalendarDisplay;
    CollectionsDisplay;
    }
    }
    }

    and inside Main.as:

    public function Main()
    {
    IterableClasses;

    }

    And then all of those classes will work fine with getDefinitionByName.

    1. Ryan Avatar
      Ryan

      Erik,

      Thanks for taking the time to explain all that! It absolutely makes sense that the compiler wouldn’t include non-referenced items. Otherwise our swf’s would be huge.

      Cheers,

      Ryan

    2. Sachhidanand Avatar
      Sachhidanand

      Thanks Erik.

      I recently faced the same problem and the solution provided by you worked perfectly.

  3. Joshua (LaughingLeader) Avatar

    Thanks for taking the time to right this post! I’ve been running into the same problem for months now.

    A few months ago, I had stored Inventory data (for a game I’m developing) by storing the name of the item in an object (then created a save file from that). I ran into the problem with getDefinitionByName() described here. I just decided to just save the whole Inventory class I made instead, which worked.

    Then here I was today, running into the same problem as I try to create classes for my Levels (and add them into an Array) by pulling the Level Class names from an external XML file (and create new classes using getDefinitionByName()). I ran into that whole “Variable is not defined” problem. I wasn’t sure what to do, as I hadn’t found a solution for this problem before, so thank you again for posting a fix for this error.

    I wish there was a way to get Flash to just automatically include the definitions of my level classes (without me having to make a reference for each class), but this will work well enough for now.

  4. John Avatar
    John

    You saved my ass dude, i cant beleive we have to put the literal path
    getDefinitionByName(“StartScreen”) as Class;

    its serious BS, but i’m glad there was a solution. Your a champ mate, long live AS3

  5. Graham Avatar
    Graham

    I’ve actually tried every single solution for this problem and none have worked.

    This line of code
    var ClassReference:Class = getDefinitionByName(item) as Class;

    Where item is a MovieClip symbol in the library called “Gem”

    This code works everywhere else in the game.
    If you include the full package path it just says Variable Gem is not defined.
    If you leave it as it, it says, variable “function Function() { is not defined”

    I tried importing the Gem movieclip a million different ways.
    Tried all of the examples outlined here, and in countless other pages.

    Eventually gave up. Had to leave the error in the game.
    It doesn’t affect the game, it’s just annoying and stupid.

Leave a Reply to Ryan Cancel reply

Your email address will not be published. Required fields are marked *