robertpenner / as3-signals Goto Github PK
View Code? Open in Web Editor NEWSignals is a new approach for AS3 events, inspired by C# events and signals/slots in Qt.
Home Page: http://flashblog.robertpenner.com/
License: MIT License
Signals is a new approach for AS3 events, inspired by C# events and signals/slots in Qt.
Home Page: http://flashblog.robertpenner.com/
License: MIT License
I'm finding lately that my signals code would be a lot more controllable if the add method on ISignal returned a class called SignalMemory. This would contain a reference to the ISignal and the callback just registered, and allow me to register deregister it at a later point in time.
This is a simple class, and I use it already but I have to manually set it up. I also think the addition of this SignalMemory would also allow for easier flow control of groups of ISignals.
Any thoughts?
Here is what MySignal looks like:
package signals
{
import org.osflash.signals.Signal;
public class MySignal extends Signal
{
public function MySignal(...valueClasses)
{
super();
}
}
}
This error just started happening, can anyone help me out?
I think (for sure) in latest source (#c184b20c6f) , there's a bug in SlotList#insertWithPriority:
correct code must be:
if (priority > current.head.priority){
subClone.tail = current.prepend(slot);
return wholeClone;
}
NOT:
if (priority > current.head.priority){
const newTail:SlotList = current.prepend(slot);
return new SlotList(head, newTail);
}
(the slots from this.tail to current's previous slot are omitted!)
This bug surfaced after @destroytoday's fix for Issue 8. The removeAll() method in DeluxeSignal was working "accidentally". It's bug was cancelled out by the other bug.
The fix is to use the listenerBox properly.
I'm using Signals quite heavily in a project at the moment. I find that i'm building some support classes but i always run into the same issue:
When I want to store a signal generically I need to use signal:Object as there is no base signal class/interface.
I would like to see ISignal be the base And IDeluxeSignal extend ISignal.
It would add symmetry to the relationship between Signals and Event if Events could easily be mapped to signals.
At the moment the Signals library can use NativeSignal to trigger a signal to be fired when an IEventDispatcher dispatches an event. But this signal must have the event as the argument.
A class that allows the same functionality except that the event is mapped to another object would be a useful tool to bridge the gap between Events and Signals.
To give an example of how it might look in code:
class SomeView extends Sprite
{
public var buttonClicked:NativeSignalMapper
private var button:SimpleButton = // create the button
public function SomeView()
{
addChild(button)
// listen to the button for mouse clicks, when one is dispatched, call the mapping function
// that provides the data for the signal dispatch
buttonClicked = new NativeSignalMapper(button, MouseEvent.CLICKED,
function (event:MouseEvent):Point
{
return new Point(event.localX, event.localY)
}
)
}
}
Probably a left-over from somewhere, but the asdocs for the Signal constructor reference passing in a target (like an event dispatcher target), but the code doesn't seem to have any support for this. (And I'm not interested in support for it, since you can just pass in the target as one of the value classes!)
Using the dispatch method with the first argument a 0 results execution error of a arguments count mismatch. Any other value works fine.
AS3 does not support super.apply(null, valueClasses).
Will fix by adding logic to support super(valueClasses).
You can't addOnce to a signal from an event generated by the same signal, because in dispatch you remove all the onceListeners AFTER calling the function, which, means if the function added any new oncelisteners, these too are removed. Not sure what the best fix, but needs to be addressed.
thanks
The SignalBindings class has a verifyListener that checks whether a listener is compatible with the signal. This is a nice feature that gives great feedback so you don't screw up as a developer. However, because the verifyListener checks the Function(listener).length
parameter, it incorrectly justifies listeners as 'incompatible' when they use rest parameters.
I was happily/deviously stringing together signals by adding one signal's dispatch method as a listener to another signal. Like originalSignal.add(bubbleSignal.dispatch)
. However, this will fail as soon as you have Signals with parameters, because the dispatch
method has a rest parameter.
I couldn't be the first to try this scenario, so is there an alternative to add rest-parameter-functions as listeners?
Cheers, love the signals,
Eric-Paul.
Just updated my signals to the current head ( commit 6e33200 ) and my listeners seem to be firing in reverse order to that with which they were added.
I guess I could add priorities, or just reverse the order they are added, but hey....
cheers
Signal and DeluxeSignal throw ArgumentError on dispatch(null). The values are nullable, so the signal should be as well.
NativeSignal should not allow null because it blows up in EventDispatcher.dispatchEvent().
Hey, I was wondering if there was a reason why internally Signals uses Arrays over the more efficient Vector.<> type. Is this for backward compatibility reasons? Would it make sense to make the switch? Or are there forks out there that have made this change? :)
valueClasses is in ISignal but not IDeluxeSignal
I think I have come across a bug in the priority signal. I did a series of unit tests to narrow it down and this one failed to fill 5 slots.
[Test]
public function positive_to_negative_priority_values():void
{
_signal.addWithPriority(testFunction_1, 1);
Assert.assertEquals(_signal.numListeners, 1);
_signal.addWithPriority(testFunction_2, 0);
Assert.assertEquals(_signal.numListeners, 2);
_signal.addWithPriority(testFunction_3, -1);
Assert.assertEquals(_signal.numListeners, 3);
_signal.addWithPriority(testFunction_4, 0);
Assert.assertEquals(_signal.numListeners, 4);
_signal.addWithPriority(testFunction_5, 1);
Assert.assertEquals(_signal.numListeners, 5);
}
if you use 1, 0 then -1 as signal priorities in that order in a proper test case it should be reproducible.
I love signals btw. building a game with them :)
Correct me if I'm wrong but not able to bubble signals to more than just the immediate
parent
This is a show stopper for me...since I rely heavily on bubbling in all my projects.
Anyone have a workaround?
Please, can you create a README file?
Thanks
In Flash IDE I was getting an error message for lines 150, 158 and 159 in Signals.as
1049: Illegal assignment to a variable specified as constant.
Changed "const" to "var", works now.
Function Signal.remove() can be optimized to this:
public function remove(listener:Function):void
{
var index:int = listeners.indexOf(listener);
if (index == -1) return;
listeners.splice(index, 1);
delete onceListeners[listener];
}
Sorry to post this here but I'm new to git and version control and I have NO IDEA of where to post or commit.
This only occurs when the target EventDispatcher is used directly to dispatch the event, rather than through the NativeSignal's dispatch().
Reported by @iainlob: http://twitter.com/iainlobb/statuses/4994185925
Hi,
I don't know if this is the right place to ask a question like this, please forgive me.
I have been using DeluxeSignals to bubble events up through my application, always being dispatched from a class extending Sprite.
Now I need to dispatch an event from a class that does not extend a display object. The the same way of dispatching DeluxeSignals and having the onEventBubbled method 'catch' the event, does not seem to work.
I could make a bunch of signals and have them relay to eachother all the way to the top, but it is messy.
Any ideas?
Thanks,
Sam
No longer compiles in Flash CS4 due to inner classes. General info about issue: http://blog.ajaychhaya.com/2009/10/07/cannot-use-interface-and-internal-class-together-in-flash-cs4/
Even though this is a bug in CS4, I still think the private classes should be removed, otherwise a large portion of developers can't use it.
I found a simple fix - in the dispatch function change:
if (!eventObject)
listener();
to:
if (eventObject == null)
listener();
Can you add this to the main trunkage? Haven't checked but maybe this affects native signal too.
hello,
I am extensively using casalib for developing projects. It's destroy method is very usefull in clearing events and good for better memory management. But signals is not working with casalib. Casalib destroy() method not clearing the events. So am doubt about the event added using signals and it's memory management.
regards
Like the fact I can declare Signals in MXML, be great if I could also declare NativeSignals in MXML also.
cheers
My fork is here: https://github.com/neilmanuell/as3-signals
I have created a PrioritySignal: https://github.com/neilmanuell/as3-signals/blob/master/src/org/osflash/signals/PrioritySignal.as
And a TestRunner: https://github.com/neilmanuell/as3-signals/blob/master/tests/org/osflash/signals/PrioritySignalTestsRunner.as
The PrioritySignal is simply a Signal subclass, implementing IPrioritySignal and the relevant priority methods cut and pasted from the DeluxeSignal
I have reverted the Signal back to prepending its bindings, and removed the new order-of-dispatch tests from ISignalTestBase
I have three groups of tests,
Each group has 6 tests, basically exactly the same except that the order of addition is different.
The logic being that changing the order of addition should not change the order of dispatch, as dispatch should depend upon the priority set.
in each group tests 2 & 5 fail, as listenerA is never dispatched.
I have not looked at the under lying code, as to be quite honest the SignalBindingList is a bit intimidating
I'm also a noob at this testing lark, so bare that in mind, as I may have made a mistake (though I don't think so) :-/
Reported by jgondek:
http://groups.google.com/group/as3-signals/browse_thread/thread/d006f3d2fe9af6
I found, that when I change the target property of a NativeSignal, all
listeners attached to the previous target react on the event of the
previous and current target.
var nativeSignal:NativeSignal = new NativeSignal( this,
Event.ENTER_FRAME );
nativeSignal.add( onThisEnterFrame );
nativeSignal.target = new Sprite();
nativeSignal.add( onThatEnterFrame );
private function onThisEnterFrame( $event:Event ):void
{
trace( "onThisEnterFrame" );
}
private function onThatEnterFrame( $event:Event ):void
{
trace( "onThatEnterFrame" );
}
onThisEnterFrame
onThatEnterFrame
onThisEnterFrame
onThatEnterFrame
onThisEnterFrame
onThatEnterFrame
onThisEnterFrame
onThatEnterFrame
...
I noticed that the ISignal interface does not define removeAll() but does define remove(f). Is there a reason for this?
I would like to propose that removeAll be added to an interface so that users can program to an interface rather than program to the concrete classes Signal and DeluxeSignal.
File: DeluxeSignal.as (org.osflash.signals.DeluxeSignal)
Line: 114
https://github.com/robertpenner/as3-signals/blob/master/src/org/osflash/signals/DeluxeSignal.as#L114
remove() method in NativeSignal hasn't delete onceListeners flag correctly.
Hi, firstly thx for your great project, it saves me lots of time, you are a great developer :)
I have an issue, when I published my project with Flashbuilder 4.7(SDK3.4) and it appeared the following error:
TypeError: Error #1034: 强制转换类型失败:无法将 org.osflash.signals::SlotList@9d633e1 转换为 org.osflash.signals.SlotList。
at org.osflash.signals::SlotList$cinit()[I:\Flash\projects\flash\classes\org\osflash\signals\SlotList.as:14]
at global$init()
but after I changed the followings codes which in SlotList:
public static const NIL:SlotList = new SlotList(null, null);
to:
public static var _NIL:SlotList;
public static function get NIL():SlotList
{
if(!_NIL) _NIL = new SlotList(null, null);
return _NIL;
}
and also change the 2 NIL to _NIL which in constructor function.
NOW IT WORKS!
I struggled with it 2 days and now find this solution.
Do you have any other good suggestion or did I do something wrong?
The fix checks if the listener index is -1 prior to splicing.
Reported by @destroytoday.
When a listener function is just a vararg (doSomething(...args:Array)), the arguments.length of that function returns 0, which is failing verifyListener check in SignalBinding.
I'm not sure if there is a way to detect varargs in a Function, but it would be great to be able to bypass this check.
I get an ArgumentError while trying to add listener that has ...args as argument. Error says 'Listener has 0 arguments but it needs at least 1 to match the given value classes.' It seems ...args is ignored in counting of arguments. I'm quite sure that there's no way to check it or ignore if there's ... argument.
For some reason this program loses its connection. i have checked every cable and internet line i can think of. i have even tried playing it from your website. please tell me what i can do to fix this issue?
const nativeSignal : ISignal = new NativeSignal(dispatcher, Event.ENTER_FRAME);
nativeSignal.add(function(event : Event, value : int) : void { /* do something */ }).params = [1];
Will throw an error, because native signal expects one argument.
Just thought I'd mention this:
the use of Event.EXIT_FRAME and Event.FRAME_CONSTRUCTED in DisplayObjectSignalSet
means that I have to compile specialised SWC for back compatibility (I'm targeting 9).
This may lead to unnecessary confusion.
at the moment I just need the pure Signals (Signal, SimpleSignal, PrioritySignal) so I have compiled a SWC with just those.
I was wondering if there has been any discussion re architecture/deployment of SWCs?
This is a similar issue:
millermedeiros/js-signals#29
It be nice to have an event buss, to find an emitter, or a group of emitters (so I can observe them)
This don't work:
public function request( command:String , data : Object = null ):void
{
signalMapper = new NativeMappedSignal(
this._service,
HttpResponseEvent.COMPLETE,
HttpResponseEvent,
ResourceModel,
Object
).mapTo( onResponseMap, data );
}
public function onResponseMap( event:HttpResponseEvent ):ResourceModel
{
return new ResourceModel();
}
In Tests(tests/org/osflash/signals/natives/NativeMappedSignalFunctionArgTest.as) use just String, int, Number and Array, just this types is supported?
Error returned:
ArgumentError: Value object <function Function() {}> is not an instance of <[class ResourceModel]>.
at org.osflash.signals::DeluxeSignal/dispatch()[D:\_github\as3-signals-0.8\src\org\osflash\signals\DeluxeSignal.as:148]
I'm using:
signals 0.8
robotlegs 1.5.2
signals-extension 0.2.4
Thanks for all, i'm working in this... 👍
now it's:
public class NativeSignal implements INativeSignalOwner
should be: public class NativeSignal implements INativeSignalOwner, ISignal
why:
thanks
I really like as3-signals, and I like that dispatch is an synchronous call to the listeners, but every once in a while it comes handy to be able to delay the call to the listeners for the next frame enter events. I wrote a simple class that extends Signal and dispatches asynchronously.
Here it is if you are interested in incorporating it or it's concept to this great library.
package org.osflash.signals { import flash.display.Shape; import flash.display.Stage; import flash.errors.IllegalOperationError; import flash.events.Event; import flash.events.EventDispatcher; import flash.utils.Dictionary; public class AsyncSignal extends Signal { protected var valueObjectsQueued:Array; // Queue of objects that will be sent to the listeners protected var enterFrameShape:Shape; // Shape used to generarte on enterframe. Does not have // To be added to stage. /** * Creates a Signal instance to dispatch value objects. This AsyncSignal delays * the call to the listeners when using dispatch until the next frame, basically making * the dispatch an asyncronous call. * @param valueClasses Any number of class references that enable type checks in dispatch(). * For example, new AsyncSignal(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 AsyncSignal(...valueClasses) { valueObjectsQueued = new Array(); enterFrameShape = new Shape(); // Cannot use super.apply(null, valueClasses), so allow the subclass to call super(valueClasses). if (valueClasses.length == 1 && valueClasses[0] is Array) valueClasses = valueClasses[0]; super(valueClasses); } /** @inheritDoc */ override public function dispatch(...valueObjects):void { // Validate value objects against pre-defined value classes. var valueObject:Object; var valueClass:Class; var numValueClasses:int = _valueClasses.length; if (valueObjects.length < numValueClasses) { throw new ArgumentError('Incorrect number of arguments. Expected at least ' + numValueClasses + ' but received ' + valueObjects.length + '.'); } for (var i:int = 0; i < numValueClasses; i++) { // null is allowed to pass through. if ( (valueObject = valueObjects[i]) === null || valueObject is (valueClass = _valueClasses[i]) ) continue; throw new ArgumentError('Value object <' + valueObject + '> is not an instance of <' + valueClass + '>.'); } if (!listeners.length) return; if (!enterFrameShape.hasEventListener(Event.ENTER_FRAME)) { enterFrameShape.addEventListener(Event.ENTER_FRAME,callListenersAsync,false,0,true); } valueObjectsQueued.push(valueObjects); } /** * Function that gets called when the next frame renders and it will the call the listeners * @param event is the enter frame event that gets removed inmediatelly. No reason to * */ protected function callListenersAsync(event:Event):void { enterFrameShape.removeEventListener(Event.ENTER_FRAME,callListenersAsync); listenersNeedCloning = true; while (valueObjectsQueued.length > 0) { callListener(valueObjectsQueued[0]); valueObjectsQueued.splice(0,1); } listenersNeedCloning = false; } /******************************* * The actual call to the listeners * @param valueObjects is the array of parameters */ protected function callListener(valueObjects:Array):void { //// Call listeners. // During a dispatch, add() and remove() should clone listeners array instead of modifying it. var listener:Function; switch (valueObjects.length) { case 0: for each (listener in listeners) { if (onceListeners[listener]) remove(listener); listener(); } break; case 1: for each (listener in listeners) { if (onceListeners[listener]) remove(listener); listener(valueObjects[0]); } break; default: for each (listener in listeners) { if (onceListeners[listener]) remove(listener); listener.apply(null, valueObjects); } } } } }
Let me start off by saying you've done an awesome job with this project Robert, it's well thought out and the documentation is excellent.
I know that in the registerListener function it checks the length of the listener function against the amount of value classes for the Signal, which is vital, but is there any way to determine if the listener is using ...params? It would be good to be able to add listeners that make use of this. I can provide examples of how/why I'm using it in this way if you need it.
Cheers,
Mark
If you have lots of objects with signals, object creation can become a bottleneck.
How about lazily creating the onceListeners Dictionary, since this isn't always used?
If I try to write some sort of manual bubbling (redispatching) code:
someObject.someSignal.add(mySignal.dispatch);
I get this kind of error:
Exception fault: ArgumentError: Listener has 0 arguments but it needs at least N(>0) to match the given value classes.
at org.osflash.signals::Signal/registerListener()[.../as3-signals/src/org/osflash/signals/Signal.as:191]
at org.osflash.signals::Signal/add()[.../as3-signals/src/org/osflash/signals/Signal.as:75]
Is possible to do something about this?
One problem that comes up often is how to tie a set of generic buttons to different values, so when you click each button the same function is ultimately called, but with different arguments. Solutions I know of include doing a "switch" on which button it was, doing a dictionary look-up with the button as the key, storing the values in the button itself and returning in a custom event, storing the values in some kind of mediator, or setting the onClick to an anomymous function enclosing the function call arguments. With AS2 delegate/proxy classes this was simple because you could add the arguments to the delegate.
Would it be within the scope of Signals to add a way of doing this? Or is an anonymous function the best way to achieve this? Or is this too bad practice to even consider?
This post talks about the problem: http://wildwinter.blogspot.com/2007/04/come-back-delegate-all-is-forgiven.html
I'm not sure if we can really classify this as an issue, but I figured I'd bring it up. Signals that expect the IEventDispatcher interface to be passed in cant be used in a Starling class.
clicked.eventClass = null;
clicked.dispatch(new Event('click'));
Actual: TypeError: Error #1009: Cannot access a property or method of a null object reference.
Expected: eventClass should default to Event when set to null and dispatch without error.
With the new changes and simplifications to Signal (which are great), and the focus on delivering value objects, I'd like you to reconsider my request to add arguments to the add() function, or create a new type of signal to do this. I honestly think this could be a killer feature.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.