I got this class, let's call it: Klass.
The class Klass has a parameter for its constructor that is an array with a default value of null.
I create an object of the class Klass inside another class, lets call it: "MotherClass".
Now is when it gets weird, after I instance the object Klass, the constructor of Klass gets called again, just right after the constructor of the MotherClass ends (I placed a breakpoint and I followed step by step), with null constructor parameters.
The thing is, I don't have the stack trace of anything that is calling the constructor of Klass for the second time, no clue what could be calling that constructor again...
Any ideas?
Thanks.
(Klass implements an interface, and I'm making an instance using an array, not sure if that is affecting anything)
added code as requested:
this is the class MotherKlass:
public class Unit extends EntityVO{
public function Unit(level:int = 1)
{
//init vars and stuff
//...
//
initLevelData();
applyLevel = level;
}
private function initLevelData():void {
levelData[1] = [500, [[Spawn, this.entityToSpawn.type, this.entityToSpawn.level, 120]], "unit_level1"];
levelData[2] = [1000, [[Spawn, this.entityToSpawn.type, this.entityToSpawn.level, 90]], "unit_level2"];
levelData[3] = [2000, [[Spawn, this.entityToSpawn.type, this.entityToSpawn.level, 80]], "unit_level3"];
levelData[4] = [5000, [[Spawn, this.entityToSpawn.type, this.entityToSpawn.level, 60]], "unit_level4"];
}
override public function set applyLevel(level:int):void {
power = power / maxPower * levelData[level][0];
maxPower = levelData[level][0];
behavior = levelData[level][1];
for (var i:int = 0; i < behavior.length; i ++){
_behaviorSteps[i] = new behavior[i][0](behavior[i].slice(1));
_behaviorReqs.push(_behaviorSteps[i].req);
}
}
}
}
}
and this is Klass:
public class Spawn {
public class Spawn implements IBehavior
{
private var _entityType:String;
private var _entityLevel:int;
private var _spawnRate:int;
public function Spawn(params:Array = null){
//had to put the if because of the second weird call to the constructor with null
if(params){
_entityType = params[0];
_entityLevel = params[1];
_spawnRate = params[2];
}
}
}
}
}
Ok, this is what appears to be happening:
You have a setter for applyLevel which is overriding the super class' setter. I think your super class setter is also getting executed. Some observations that lead me to this conclusion:
your setter method overrides the super class method, but no where does it do super.applyLevel = level. This means that in the super class, the storage variable that should be keeping the level value is uninitialized. An uninitialized integer in Actionscript defaults to 0.
you mention that the second invocation of Spawn's constructor has no parameters. This occurs because your array of levelData starts out at index 1. So index 0 of this array is null.
so the super class version of the applyLevel setter method is passing in the null element from above.
I think these facts are 100% correct.
What's not clear to me is who is calling the super class' version of applyLevel Perhaps the super class (EntityVO) is doing that in it's constructor ... Hopefully this should be enough to point you in the right direction.
I'm receiving an instance of the class Unit throught Cirrus, and using RegisterClassAlias to deserialize the object. When I do that, seems like an instance of Spawn must be automatically instantiated for some reason. That is why you cant pass ojbects without default arguments. In this case, it throws an error because I'm using (params[0]) the argument that is null. I use Cirrus in other parts of my code, and it works ok because there are all ints and strings in their parameters constructors.
Related
So I have a method that takes in a String and then is suppose to set the dynamic textbox on a button to said String.
public function setText(caption:String) {
this.btext.text = caption;
}
I really don't understand why this method is producing a 1119 error.
Access of a possibly undefined property btext through a reference with static type Button.as
The instance name of the Dynamic Textbox is btext and I have tried deleting the textbox and making a new one however this still produces a 1119 error. I also read on another stack question that trying this['btext'].text = caption; which gave me plenty of runtime errors.
Basically what am I doing wrong?
Thank you for any help.
EDIT
Here is the code I am using, and I create an instance of button add it to the stage and store it in an array with this code.
Code to create button
this.buttonArray.push(this.addChild(weaponButton));
Button.as
package {
import flash.display.MovieClip;
import flash.filters.*;
public class Button extends MovieClip {
public function Button() {
}
public function setPosition(xpos:int, ypos:int) {
this.x = xpos;
this.y = ypos;
}
public function setScale(xScale:Number, yScale:Number) {
this.scaleX = xScale;
this.scaleY = yScale;
}
public function addDropShadow():Array {
var dropShadow:DropShadowFilter = new DropShadowFilter(2,45,0, 1,4,4,1,1,true);
return [dropShadow];
}
public function removeDropShadow():Array {
return null;
}
public function setText(caption:String) {
this.btext.text = caption;
}
}
}
As you have stated btext is an instance name of an object. Here is where I assume btext is an object you created in your library.
In your class you are doing 2 things wrong. So lets examine your method.
public function setText(caption:String) {
this.btext.text = caption;
}
The first thing wrong is you are using "this". "this" is a reference to the current instance of the class you are in. And you are saying btext is a property on said instance. Which as I am assuming it is not because you defined btext as an object in your library. This will give you the property is undefined error you are gettting.
Now the second issue at hand is you are about to ask "OK how do I reference btext in my class then". What you need to know is that only objects added to the display list IE:stage can access objects via the stage.
You can do this 3 ways.
The first way is to pass a reference to the button into the class and store it as a property of the class.
The second way is to add your class to stage and in the class listen to the addedToStage event. At that time you can then access the object.
MovieClip(root)["btext"].text
The first 2 methods are not good practice since btext is not apart of the class and a general rule of thumb would be to encapsulate your class.
To make this work what you could do is have your class assign the value to a property in your class then fire an event and make the parent of this class listen to that event then just grab the value and assign.
Here is some suggested reading
I think the variable btext doesn't exist at all, or is it inherited from Movieclip?
I have a singleton class that looks something roughly like this (only with more bindable public properties):
public class Session extends EventDispatcher
{
private var _Id:String;
private static const _instance:Session = new Session( SingletonLock );
private static const SESSID_CHANGED:String = 'SessionIdChanged';
public function Session( lock:Class ){
//SingletonLock is an empty class not available outside this file
if( lock != SingletonLock ){
throw new Error("Don't instantiate Session. Use Session.instance");
}
_Id = "";
}
public static function get instance():Session{
return _instance;
}
// Changes a blob object (from the server xml for sessions) to a session object
public function updateFromXMLObj(s:ObjectProxy):void
{
_instance.Id = s.Id;
}
[Bindable(event=SESSID_CHANGED)]
public function get Id():String{
return _Id;
}
public function set Id(new_id:String):void{
if(this._Id != new_id){
this._Id = new_id;
this.dispatchEvent(new Event(SESSID_CHANGED));
}
}
public function registerOnSessionChange(listener:Function):void{
addEventListener(SESSID_CHANGED,listener);
}
public function unregisterOnSessionChange(listener:Function):void{
removeEventListener(SESSID_CHANGED,listener);
}
}
The idea is that in some mxml code, I have a databinding expression like the following:
<mx:HTTPService id="homeReq" url="{URLs.homepath(Session.instance.Id)}" ... />
where I want the url for homeReq to be updated when the sessionId changes. In addition, other parts of the code (written in Actionscript) need to be able to register their listeners for when the sessionId changes, so they call registerOnSessionChange and unregisterOnSessionChange to manage those listeners.
The abnormal behavior I'm discovering is that the event listeners registered through registerOnSessionChange are indeed being called when the session Id changes, but the MXML data binding expression is not updating. I've tried all combinations of dispatching the event during the capture phase, and making it not cancelable, but to no avail. My understanding of [Bindable (event= ...)] is that the MXML should update the url string when the event specified is dispatched, so what am I doing wrong or misunderstanding?
Note: I realize there are lots of different ways of doing the singleton pattern in Actionscript, but unless the way I am doing it is actually causing my problem somehow, I'd appreciate not getting sidetracked by discussing alternatives.
I think that {URLs.homepath(Session.instance.Id)} this is not binding to a variable instead is executing a method of an object, have you tried to do something like this:
[Bindable]
private var _url:*
Then setting the initial value to _url at init or complete:
_url = {URLs.homepath(Session.instance.Id)};
Linking to the binded variable in the MXML
<mx:HTTPService id="homeReq" url="{_url}" ... />
Then updating the _url variable should automatically update the HTTPService url...
Make an MXML form containing a combobox for course number of 5th semester. On selecting the coruse, display the course name and max marks for the selected course.
Data Binding: <mx:Binding>
Possibly bad practice but I'm not well versed in software design anyway (I'm sure this question would have been asked before but I can't seem to find the right terminology)...Anyhow, it's just another curiosity of mine I'd like to have answered.
So I have worked in a way where I type a base class variable to type Object or Sprite or something similar so that in my subclasses, I can instantiate my custom classes into them and store it. And when I access it, I just cast that variable to ensure I can access the methods.
Take this example, so that you know what I'm talking about:
public class BaseClass
{
protected var the_holder_var:Object;
public function BaseClass()
{
//Whatever abstract implementation here...
}
}
Now, my subclasses of that base class usually use an interface but for simplicity sake, I'll just write it without it.
public class AnExtendedClass extends BaseClass
{
public function AnExtendedClass()
{
//Instantiate my own class into the base class variable
this.the_holder_var = new ACustomClassOfMine();
//Then I can use the 'hackish' getter function below to
//access the var's functions.
this.holder_var.somefunction()
}
private function get holder_var():ACustomClassOfMine
{
return this.the_holder_var as ACustomClassOfMine;
}
}
This works and I'm sure it will make some ppl cringe (I sometimes cringe at it too).
So now, my question, is there a way to recast/retype that base var in my extended subclass?
kinda like this:
public class ExtendedClass extends BaseClass
{
//Not possible I know, but as a reference to see what I'm asking about
//Just want to change the type....
override protected var the_holder_var:ACustomClassOfMine;
public function ExtendedClass()
{
//Then I can forget about having that hackish getter method.
this.the_holder_var = new ACustomClassOfMine();
this.the_holder_var.somefunction();
}
}
I was thinking of typing most of my base class vars that I use as holders as type * and retyping them as I extend the class. (I could use it here too but yeah...)
Thoughts? Comments? Ideas?
I actually think your code (apart from the hypothetical addition at the end) is pretty alright. The practise of adding accessors to solve the type issue you're dealing with is a solid one. I would advise to rename the accessor to show it is a cast, maybe get holderVarAsCustom():ACustomClassOfMine (I'm also not a big fan of the underscores, that's another language's convention), but that's personal preference. What I'd do to solve your last problem is just create a matching setter function:
private function set holderVarAsCustom(value:ACustomClassOfMine):void {
this.the_holder_var = value;
}
This way you can access the correctly typed holder var for both read and write operations with complete type safety:
holderVarAsCustom = new ACustomClassOfMine();
holderVarAsCustom.someFunction();
I would definately advise against dropping the type safety by including arrays and what not, that just makes it unstable.
I must admit that i'm a little confused as to why you want to do this, but here goes. Could you not utilise the fact that Array's can hold different data types. So something like this:
public class BaseClass
{
protected var customStorage:Array;
public function BaseClass()
{
//Whatever abstract implementation here...
}
}
You could then access it with an associative method and a property:
public class AnExtendedClass extends BaseClass
{
private static const myName:String = "myName";
public function AnExtendedClass()
{
//Instantiate my own class into the base class variable
customStorage[myName] = new ACustomClassOfMine();
objectIWant.somefunction()
}
private function get objectIWant():ACustomClassOfMine
{
return ACustomClassOfMine(customStorage[myName]);
}
}
Is that any better?
I would not try to tinker this behaviour, since you can't change the declared type of a variable once declared, no matter how hard you try.
What I do in such cases, I either cast the variable if I use it sparingly or the object it references may change, or I add another variable with the type I want and let the other variable point to the new one. Like this:
public class A {
protected var object:Object;
public function A() {
//Whatever abstract implementation here...
}
}
and
public class B extends A {
protected var other:MyClass;
public function B() {
super();
this.other = new MyClass();
this.object = this.other;
}
}
Having it this way, class A uses the object via the this.object reference, and class B can use the this.other or both. But both references point to the same object. The only issues with this are:
having two references for in the same class to the same object is ugly (so are untyped variables and casts)
if the object one of them may point can change during runtime, you must be really carefull to synchronize these changes
Is there any way for me to define implicit or explicit type conversions in ActionScript?
For instance, I want to define a conversion such that Array can cast into MyClass implicitly. If not, an explicit cast would be useful. I know I can always pass it into my constructor, but I am dealing with semantics here, and I am most interested in a conversion solution if it exists.
Type casting in ActionScript 3
Object(instanceOfOtherObject);
Works based on the valueOf property of the given class (if defined). Therefore, you can define your class MyClass as such:
package {
public class MyClass {
private var myArray:Array;
public function MyClass(inputArray:Array = null) {
myArray = (inputArray ? inputArray : new Array());
}
public function valueOf():Array {
return myArray;
}
}
}
Then you will be able to perform this typecasting:
var mc:myClass = new MyClass();
var arr:Array = Array(myClass);
To my knowledge, the reverse is not an option because the valueOf function of Array does not return an object of type MyClass. There is nothing stopping you from creating a CastableArray that extends and overrides the valueOf function of Array to make it return an instance of MyClass using the constructor I defined above, though you may run into other issues with other fundamental language components that expect an Array to return an Array in its valueOf property (comparison of objects comes to mind).
I have not done any particular testing with this next suggestion, but if MyClass extends from Array and does not define a valueOf function, it may still be possible to do the type conversion depending on the constructor of MyClass and what Flash does in circumstances when valueOf is not defined.
If a constructor takes its parameters as a vararg (...) it seems to be impossible to create a subclass that will just pass on that vararg to the superclass.
There is a related question with fix for this same situation for normal functions: Wrapping a Vararg Method in ActionScipt but I cannot get that to work with a super call.
base class:
public class Bla
{
public function Bla(...rest)
{
trace(rest[0]); // trace the first parameter
}
}
subclass:
public class Blie extends Bla
{
public function Blie(...rest)
{
// this is not working, it will
// pass an array containing all
// parameters as the first parameters
super(rest);
}
}
if I now call
var b1 = new Bla('d', 'e');
var b2 = new Blie('a', 'b', 'c');
I get the output
d
a,b,c
And I want it to print out:
d
a
Aside from actually moving the handling of the parameters to the subclass or shifting it off to a separate initializer method, does anyone know how to get the super call right?
There's unfortunately no way to call the super constructor with ... args. If you remove the super() call, it will be called by the compiler (with no arguments). arguments is also not accessible from constructors.
If you can change the method signatures, you modify the arguments to accept an Array rather than ... args. Otherwise, as you mentioned, you could move it into an initializer method.
You may use a statement like this:
override public function doSomething(arg1:Object, ...args):void {
switch(args.length) {
case 0: super.doSomething(arg1); return;
case 1: super.doSomething(arg1, args[0]); return;
case 2: super.doSomething(arg1, args[0], args[1]); return;
}
}