How pass class reference by using deluxe signals in AS3Signals? - actionscript-3

I wanna pass class reference when dispatching the deluxe signals in AS3Signals ?
My code here for dispatch,
public var signal:DeluxeSignal = new DeluxeSignal(this);
protected function button1_clickHandler(event:MouseEvent):void
{
signal.dispatch(new GenericEvent());
}
and here i listen,
protected function creComp(event:FlexEvent):void
{
viewB.signal.add(onDeluxDispatched);
}
private function onDeluxDispatched(e:GenericEvent):void
{
trace(e.target, e.signal);
trace(e.currentTarget);
trace("SignalTest.onDeluxDispatched(e)");
}
But i received null in trace.
where i am wrong ?

from the documentation of DeluxeSignal class ( https://github.com/robertpenner/as3-signals/blob/master/src/org/osflash/signals/DeluxeSignal.as )
/**
* Creates a DeluxeSignal instance to dispatch events on behalf of a target object.
* #param target The object the signal is dispatching events on behalf of.
* #param valueClasses Any number of class references that enable type checks in dispatch().
* For example, new DeluxeSignal(this, String, uint)
* would allow: signal.dispatch("the Answer", 42)
* but not: signal.dispatch(true, 42.5)
* nor: signal.dispatch()
*
* NOTE: Subclasses cannot call super.apply(null, valueClasses),
* but this constructor has logic to support super(valueClasses).
*/
public function DeluxeSignal(target:Object = null, ...valueClasses)
it has to be declared and dispatched that way :
public class ClassName {
public var signal:DeluxeSignal = new DeluxeSignal(this, ClassName);
private function dispatch():void {
signal.dispatch(this);
}
}
then retrieved that way in the referenced class :
public class Parent {
private var childClass:ClassName;
private function bindSignal() {
childClass.signal.add(signalListener);
}
private function signalListener(classReference:ClassName) {
/* do your stuff with classReference */
}
}
i ran into same issue and that worked for me

Depending on your requirements you may not need to use DeluxeSignal. I'll use Willo's example to illustrate.
public class Parent {
private var childClass:ClassName;
private function bindSignal() {
childClass.signal.add(signalListener);
}
private function signalListener(classReference:ClassName) {
/* do your stuff with classReference */
}
}
Yes, we get a class reference. But this class reference is not the one that was passed to DeluxeSignal when it was instantiated, but instead it is the one that was passed to dispatch.
public class ClassName {
/* this is not the reference to 'this' that the listener gets. in fact,
all this one does is sit inside the signal as a property */
public var signal:DeluxeSignal = new DeluxeSignal(this, ClassName);
private function dispatch():void {
signal.dispatch(this); // this is the reference that the listener gets
}
}
The reference we passed into the constructor just sits inside a public property called target.
public function DeluxeSignal(target:Object = null, ... valueClasses) {
/* the reference is set as _target and is not used anywhere else in the
class other than in the setter/getter */
_target = target;
valueClasses = (valueClasses.length == 1 && valueClasses[0] is Array) ? valueClasses[0] : valueClasses;
super(valueClasses);
}
public function get target():Object { return _target; }
public function set target(value:Object):void {
if (value == _target) return;
removeAll();
_target = value;
}
So it seems the idea is to access this property when the listener is called, using a reference to the signal:
public class Parent {
private var childClass:ClassName;
private function bindSignal() {
childClass.signal.add(signalListener);
}
private function signalListener() {
/* not passing the reference in the dispatch() call means we can
still access the target at this point by using... */
childClass.signal.target;
/* but it just feels nicer to have the reference provided as an
argument rather than as a mutable property, right? */
}
}
Technically that works but it doesn't feel great to be getting a reference from what is a mutable property.
Where it might come in handy though is when using a dependency injection framework like Robotlegs, where the signal is injected into a command. Your command wouldn't have a listener with which to be provided a reference in an argument, but it would be able to access the reference from the signal via its target property.
The way Willo used DeluxeSignal here though, you can actually use the plain old Signal class to do exactly the same thing with less overhead.
public class ClassName {
/* note: no pointless use of 'this' in the constructor. instead,
just the types we will actually be providing to the listener */
public var signal:Signal = new Signal(ClassName, String);
private function dispatch():void {
signal.dispatch(this, "Whatever else you want");
}
}
And on the other end you get this.
public class Parent {
private var childClass:ClassName;
private function bindSignal() {
childClass.signal.add(signalListener);
}
private function signalListener(classReference:ClassName, foo:String) {
/* do your stuff with classReference */
}
}
So you get the same result for typing less code and for less inheritance overhead.
Where you might want to use DeluxeSignal though, other than when needing to keep a reference to the target in your DI frameworks, is when you're using native events. DeluxeSignal overrides the dispatch method to do some extra work with those.

Related

public function access fail

I have this situation where I declare inside my main class a function that looks like this:
public class Main extends MovieClip
{
public static var instance:Main;
public function Main()
{
// constructor code
welcomeScreen();
instance = this;
}
public final function welcomeScreen():void
{
//some code in here
}
public final function startLevelOne():void
{
//some other code here
}
}
In some other class I use this statement to fire a reset:
restart.addEventListener('click', function() {
Main.instance.welcomeScreen();
});
Somehow in another class I try to use the same statement for 'startLevelOne' but it seems it is not working and gives the fallowing error:
1195: Attempted access of inaccessible method startLevelOne through a reference with static type Main.
Any ideas?
UPDATE #1
The class where I try to access the function is in full this one:
public class LevelBrief extends MovieClip
{
public function LevelBrief()
{
// constructor code
startBut.addEventListener('click', function() {
Main.instance.startLevelOne();
});
}
}
UPDATE #2
I have pasted the full code of the main definition here http://pastebin.com/s6hGv7sT
Also the other class could be found here http://pastebin.com/s6h3Pwbp
UPDATE #3
Even though the problem was solved with a workaround, I still cannot understand where was the problem.
I would recommend to leave the static instance (singleton), and work event-based. Now you make all functions public, which is not desirable. It's not that hard to use custom events. See this is how your Main class could look:
public class Main extends MovieClip
{
public function Main()
{
this.addEventListener(Event.ADDED_TO_STAGE, handleAddedToStage);
}
public function handleAddedToStage(event:Event)
{
this.removeEventListener(Event.ADDED_TO_STAGE, handleAddedToStage);
this.showWelcomeScreen();
stage.addEventListener(ScreenEvent.SHOW_WELCOME_SCREEN, handleScreenEvent);
stage.addEventListener(ScreenEvent.SHOW_LEVEL, handleScreenEvent);
}
private function handleScreenEvent(event:ScreenEvent):void
{
switch (event.type)
{
case ScreenEvent.SHOW_WELCOME_SCREEN:
{
this.showWelcomeScreen()
break;
}
case ScreenEvent.SHOW_LEVEL:
{
// event.data contains level number
this.startLevel(event.data);
break;
}
default:
{
trace("Main.handleScreenEvent :: Cannot find event.type '" + event.type + "'.");
break;
}
}
}
private function showWelcomeScreen():void
{
trace("show WelcomeScreen")
//some private code in here
}
private function startLevel(level:int):void
{
trace("start level: " + level)
//some other private code here
}
}
This is how the custom event class should look (ScreenEvent.as). Note it has an optional parameter called data. You can pass any value (objects, numbers, strings etc) into this. To the example as clear as possible, I used one event-class for both actions, you can also choose to make more specific custom events for other actions with more detailed parameters, you would have names like ScreenEvent, LevelEvent, PlayerEvent, GameEvent etc etc..
At the top of the class the (static constant) types are defined. An event should only have getters.
package
{
import flash.events.Event;
public class ScreenEvent extends Event
{
public static const SHOW_WELCOME_SCREEN:String = "ScreenEvent.showWelcomeScreen";
// event.data contains level number
public static const SHOW_LEVEL:String = "ScreenEvent.showLevel";
private var _data:String;
public function ScreenEvent(type:String, data:String):void
{
super(type);
this._data = data;
}
public function get data():String
{
return this._data;
}
override public function clone():Event
{
return new ScreenEvent(this.type, this._data);
}
}
}
.. Anywhere in your code you can dispatch the event to the stage.
// dispatch event to Main (stage). Should show welcome screen in our case
stage.dispatchEvent(new ScreenEvent(ScreenEvent.SHOW_WELCOME_SCREEN));
// show level 2
stage.dispatchEvent(new ScreenEvent(ScreenEvent.SHOW_LEVEL, 2));
I know, its a bit more code, it looks more difficult at first but if the project grows, it will help a lot. The difference with events is 'this could happen, and when it happens, do this' instead of 'do this here, do that over there'
The advantage is that if you remove the event listener in the Main class, nothing will break (loosely coupled). This makes it easier to maintain, it saves a singleton, and you have the ability to extend the Main class if you want to.
I think you wrote
Main.startLevelOne();
instead of
Main.instance.startLevelOne();
Hmm. Given your code, there is only one serious question - what is PerwollGame? You have there public static var instance:PerwollGame; and you assign it an object of type Main. Perhaps that PerwollGame has a startLevelOne() function with a different signature, that obscures your function in the Main class. Also, the other people who answered you are right as well, you should never use nested functions in your code, really put that listener of yours out from inline declaration.
Judging from your coding style and the error reported, I would assume you did this.
public static function startLevelOne():void
There is a fine line between static methods and instantiated objects.
Also never use nested functions
public class LevelBrief extends MovieClip
{
public function LevelBrief()
{
// constructor code
startBut.addEventListener('click', onMyClick )
}
public functiononMyClick (e:Event) {
Main.instance.startLevelOne();
});
}
}
I assume that when you register the listener Main.instance is not already assigned.
Did you try to trace Main instance here?
public function LevelBrief()
{
// constructor code
startBut.addEventListener('click', function() {
Main.instance.startLevelOne();
});
trace(Main.instance); // I assume Main.instance is null
}
what about if you add the listener in another method in LevelBrief like :
public function registerListeners():void{
trace("Main.instance == null? -> " + (Main.instance == null)); //not null here if called later.
startBut.addEventListener('click', function() {
Main.instance.startLevelOne();
});
}

How to access a Class in the default package from a sub package Class in Flash AS3.0

I got error message when trying to access a class in the default package from the class in its sub package. Can any one help me to sort this out.
FYI, my package structure is A -> B. I meant folder 'A' as default package and 'B' as sub package.
Thanks in advance.
Just create a object of Class A, and call class instance method, from its object.
var classAObj:A = new A();
classObj.MethodA();
I think what you're looking for is for class B to extend class A. That would look something like this in your code:
package main
{
class B extends A
{
// Code here...
}
}
Having code inside packages does not in general affect functionality, it's more an organizational tool. (Except for the internal keyword.)
how about private, protected and public ? I could not see any explanation in the other answers so here it is.
class A
{
private var _password:String;
public var username:String;
protected var serverURL:String;
public function login():void
{
// some code
callServerForLogin();
}
protected function callServerForLogin():void
{
// some code
}
}
class B extends A
{
public function B()
{
var parentPassword = super._password;
// FAILS because private and accessible only inside class A
var parentUsername = super.username
// all ok in here, public property
var parentServerURL = super.serverURL;
// all ok, because it is protected
// also we can call super.login(); or super.callServerForLogin();
}
// IMPORTANT we are also allowed to override public and protected functions
override public function login():void
{
super.login();
// we call the parent function to prevent loosing functionality;
Alert.show("Login called from class B");
}
override protected function callServerForLogin():void
{
super.callServerForLogin();
// keep also parent logic
Alert.show("calling protected method from B");
}
}
// ---- Now considering you declare an object of type B you can do the following
var bObj:B = new B();
// access public properties and call public functions from both B and A
bObj.username = "superhero";
bObj.login();
// will get compile error for next lines
bObj.serverURL = "host.port";
bObj.callServerForLogin();

action script 3 - simplifying the code by implementing the OOP (probably abstract hack)

I apologize in advance if my question is not clear, because I don't know how to put this.
What I am trying to do is to reduce few lines of repeated code by implementing various OOP methods/concepts.
The problem
I have few set of of classes which has initialization process. So, I am implementing an init() method in all those classes. From the calling class (main), these objects will be instantiated and init() method of each object is called in the the order and call some other process after all of them are initialized.
Something like this
public function mainClass(){
_obj1 = new Class1();
_obj1.init();
_obj2 = new Class2();
_obj2.init();
_obj3 = new Class3();
_obj3.init();
doSomething();
}
Well, its not a big deal, but some of the classes' init() methods are asynchronous and I need to add an event listener to get notified when they have finished initialization.
I tried that by extending EventDispatcher for each of those classes and dispatch event and handle it. I even implemented a logic to handle multiple asynchhnous calls by maintaining a counter.
It will be a painful job for me whenever I need to add a new class. I thought I could untilize OOP and reduce and simplify the code.
So I came up with some thing like this, which is currently not possible (abstract class).
abstract class Initializable
{
private var _callBack:Function;
//implement initializaton process in this method
function init(callback:Function=null):void;
protected function get callback():Function{
return _callBack;
}
protected function set callback(func:Function):void{
_callBack = func;
}
protected function onComplete():void{
if (_callBack){
_callBack(this);
}
}
}
This is the main problem for me, as you know abstract class is not allowed in AS3, and the "this" refers to the Initializer class but not its subclass I guess.
This is what I am asking for your help (for the hack)
I need it very much to make my system design simple and flexible, because I can extend the solution to allow mass synchronous initialization which will allow to easily queue up all objects in the order and call init() one after the other in the order in which they are added.
The mass initializer which takes care of handling the asynchronous job
public class MassInitializer
{
private var _objList:Array; //holds objects
private var _callBacks:Array;
private var _onComplete:Function;
public function MassInitializer()
{
_objList = new Array();
}
public function add(obj:Initializable,callback:Function=null):void{
_objList.push(obj);
_callBacks.push(callback);
}
public function init():void{
for (var i:int = 0;i < _objList.length;i++){
_objList.init(this);
}
}
private function onProgress(obj:Initializable):void{
//do updates here
for (var i:int;i<_objList.length;i++){
var obj:Initializable = _objList[i];
var fun:Function = _callBacks[i];
//update progress
if (fun){
fun(obj);
}
_callBacks.splice(i,1);
_objList.splice(i, 1);
}
if (_objList.length == 0){
onComplete();
}
}
private function onComplete():void{
_onComplete(this);
}
}
the main (manager/caller) class (ClassA, ClassB are subclasses of Initialzable class)
public class MainClass
{
private var _obj1:ClassA;
private var _obj2:ClassB;
public function MainClass()
{
_obj1 = new ClassA();
_obj2 = new ClassB();
}
public function init():void{
var initManager:MassInitializer = new MassInitializer();
initManager.add(obj1);
initManager.start();
}
}
probably I am trying to (or want to )implement an observer pattern, but I don't want to confuse you by saying it in advance. Oops I said it? please ignore.
You can emulate abstract classes in ActionScript by enforcing method overrides: Just throw an error if the "abstract" method is called. I like to also implement an interface, but that's not a must, of course:
public interface Initializable
{
function init (callback : Function = null) : void;
function get callback () : Function;
function set callback ( callback : Function ) : void;
}
public class AbstractInitializableImpl implements Initializable
{
private var _callBack:Function;
protected function init(callback:Function=null):void {
throw new Error ("You must implement the init() method!");
}
protected function get callback():Function {
return _callBack;
}
protected function set callback(func:Function):void {
_callBack = func;
}
protected function onComplete():void {
if (_callBack){
_callBack(this);
}
}
}
It's not a 'hack'. It's also very simple. Make each subclass implement an interface, instead of extend an abstract class.
Here is the adobe reference on AS3 interfaces.

Overriding a public variable with set

I have a base class like this
class Base {
public var space:Number;
}
which gets extended by
class Desc extends Base {
override public function set space( space:Number ):void {
//code
}
}
This doesn't compile. Say, you don't have control of the base class, what ways is there implement the same thing?
The obvious is create a function setSpace(), but this object is being embedded in an already existing system that use the public space.
Thanks in advance.
Your base class should be defined that way:
class Base {
// Don't use public variables. Make them private and define setters and getters
private var space_:Number;
public function get space():Number {
return space_;
}
public function set space(v:Number):void {
if (space_ === v) return;
space_ = v;
}
}
And then it can be overriden that way:
class Desc extends Base {
override public function set space( space:Number ):void {
//code
}
}
Edit:
I missed the part where you say you don't have control over the base class. In that case, hope that space is defined as a getter/setter (it should be if the class is implemented properly). If not, you'll indeed have to use a function such as getSpace and setSpace.
From Adobe:
Class member variables that are declared using the var keyword cannot
be overridden in a subclass.
Using a setter is not an option in your case. If you need to preserve the interface, use composition instead of inheritance:
class Desc {
private var _base:Base;
public function set space(space:Number):void {
//code
this._base.space = space;
}
}

Listen to any change in the values of an Object in Actionscript

I have an Object in actionscript which has a few dozens of properties each of which is defined to be bindable and has its own change event. I would like to listen to any changes made to this object without having to add a listener to all of its properties. Is there a way in actionscript using which I can listen to any change in the values of an Object ?
Thanks,
-A
You can use the PropertyChangeEvent on a [Bindable] class to listen for any property changes. As long as you're using the get/set properties.
package
{
[Bindable]
public class Person
{
private var _firstName:String;
private var _lastName:String;
private var _age:Number;
public function get firstName():String
{
return _firstName;
}
public function set firstName(value:String):void
{
_firstName = value;
}
public function get lastName():String
{
return _lastName;
}
public function set lastName(value:String):void
{
_lastName = value;
}
public function get age():Number
{
return _age;
}
public function set age(value:Number):void
{
age = value;
}
public function Person()
{
// empty constructor
}
}
}
Then, in your using class add the event listener.
public var p:Person;
private function addListener():void
{
p = new Person();
p.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, onPropertyChange);
}
private function onPropertyChange(event:PropertyChangeEvent):void
{
trace(event.property + " " + event.kind + " " + event.oldValue + " " + event.newValue);
}
I don't think there is a way to listen to listen to an event without adding a listener. However, there is no reason you can't use the same listener function for ever event change. Adding the event listeners should be relatively trivial:
myObject.addEventListener('property1Changed',myChangeHandler)
myObject.addEventListener('property2Changed',myChangeHandler)
etc... etc..
You could also have each property fire a generic change event in addition to the property specific change event. Although tedious, this should be an quick cut and paste job.
One way could be to call an objectChanged() function on each setter.
public function set property1(arg) : void{
property1 = arg;
objectChanged();
}
Edit: You could make the class implement IPropertyChangeNotifier