Code

AS3, Dictionary & Weak Method Closures

This is going to be a technical post so those of you not of the code persuasion look away now..

Okay great, now those guys have gone I can get down to it.

Some of my recent work on the SWFt project has revolved around the use of Robert Penners AS3Signals. If you dont know what Signals are I strongly reccomend that you check out Roberts blog for more info. In brief, they are an alternative to the Events system found in Flash, based on the Signal / Slot pattern of Qt and C# they are much faster and more elegant (my opinion) than native events.

I have been trying to incorporate signals in SWft for both the elegance and performance gains that they bring, however there is an issue that was brought to my attention by Shaun Smith on the mailing list. The issue is that my current use of them will cause memory leaks.

I realised that this too would apply to the work I had been doing using the RobotLegs and Signals libraries. RobotLegs (for those of you that dont know) is an excellent Dependency Injection framework inspired by the very popular PureMVC framework. I have blogged before about its excellence. Signals have been incorporated into RobotLegs as a separate ‘plugin’ by Joel Hooks in the form of the SignalCommandMap. The SignalCommandMap does as the name implies, it allows you to map signals to commands so that whenever a mapped signal is dispatched then the corresponding command is executed.

Its a very nice, elegant, solution to RIA development. However there is one catch. I have so far been using signals such as:

  1. public class MyMediator extends Mediator
  2. {
  3. // View
  4. [Inject] public var view : MyView;
  5.  
  6. // Signals
  7. [Inject] public var eventOccured : ViewEventOccuredSignal;
  8. [Inject] public var modelChanged : ModelChangedSignal;
  9.  
  10. override public function onRegister():void
  11. {
  12. view.someSignal.add(eventOccured.dispatch);
  13. modelChanged.add(onModelChanged);
  14. }
  15.  
  16. protected function onModelChanged()
  17. {
  18. view.updateView();
  19. }
  20. }

So here we can see a typical use of Signals in a mediator. There are two things going on here that are of concern, lets break them down.

Firstly on line 12 we are listening to a signal on the view, then passing on the event directly to an app-level event, notice how nice and clean this is, this is what I love about using RL & Signals. Line 13 we are listening for an app-level signal for a change on the model then updating the view to reflect this.

It all looks well and good but unfortunately in its current state it could cause a memory leak. This is because we are listening to events on signals without then removing the listen. For example, we are listening to the app-level event on line 13 “modelChanged.add(onModelChanged);” so now the “modelChanged” signal has a reference to this Mediator. This will cause a leak when the View is removed from the display list. Normally the mediator would also be make available for garbage collection, however, because the singleton Signal has a reference to the Mediator it cannot be removed.

The same goes for line 12. Suppose the “ViewEventOccuredSignal” that is injected is not a singleton and is swapped out for another instance it could not be garbage collected as the “view.someSignal” has a reference to its dispatch function.

Realising this problem I knew that the solution was simply to be careful and add a “onRemoved” override function in my Mediator then clean up by removing the signal listeners. However I like the simplicity and beauty of current way of doing things so I started to wonder if there was another way.

I started thinking about whether I could use weak references with the Signal. If I could then I wouldnt have to worry about cleaning up as the Signal wouldnt store any hard-references to the functions and so the listener would be free for collection. After some digging however I realised that there was no option for weak listening in Robert Penners AS3Signals.

I thought to myself why the hell not? I knew that the Dictionary object in AS3 has an option to store its contents weakly so I thought so long as you don’t require order dependant execution of your listeners it should be possible to store the listener functions in a weakly referenced Dictionary.

It was at this point that I noticed Roberts post on the subject of weakly referenced Signals: http://flashblog.robertpenner.com/2009/09/as3-events-7-things-ive-learned-from.html. In it he references Grant Skinners post concerning a bug with storing functions in a weakly referenced Dictionary.

From Grant’s post:

Note that there is a known bug with Dictionary that prevents it from operating correctly with references to methods. It seems that Dictionary does not resolve the method reference properly, and uses the closure object (ie. the “behind the scenes” object that facilitates method closure by maintaining a reference back to the method and its scope) instead of the function as the key. This causes two problems: the reference is immediately available for collection in a weak Dictionary (because while the method is still referenced, the closure object is not), and it can create duplicate entries if you add the same method twice. This can cause some big problems for things like doLater queues.

This was starting to look bad for my idea. Me being me however, I thought I knew better, and that post was written pre Flash 10 so I thought to myself: perhaps its been fixed in Flash 10. So I set to work coding a simple example.

I created a very simple Signal dispatcher:

  1. package
  2. {
  3. import flash.events.EventDispatcher;
  4. import flash.utils.Dictionary;
  5.  
  6. public class SimpleDispatcher
  7. {
  8. protected var _listeners : Dictionary;
  9.  
  10. public function SimpleDispatcher(useWeak:Boolean)
  11. {
  12. _listeners = new Dictionary(useWeak);
  13. }
  14.  
  15. public function add(f:Function) : void
  16. {
  17. _listeners[f] = true;
  18. }
  19.  
  20. public function dispatch() : void
  21. {
  22. for (var o:* in _listeners)
  23. {
  24. o();
  25. }
  26. }
  27. }
  28. }

And a very simple listening object:

  1. package
  2. {
  3. public class SimpleListener
  4. {
  5. public function listen(d:SimpleDispatcher) : void
  6. {
  7. d.add(onPing);
  8. }
  9.  
  10. protected function onPing() : void
  11. {
  12. trace(this+" - ping");
  13. }
  14. }
  15. }

And then a simple Application to hook it all together:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
  3. xmlns:s="library://ns.adobe.com/flex/spark"
  4. xmlns:mx="library://ns.adobe.com/flex/mx">
  5.  
  6. <fx:Script>
  7. <![CDATA[
  8. import mx.controls.List;
  9.  
  10. protected var _dispatcher : SimpleDispatcher = new SimpleDispatcher(true);
  11. protected var _listener : SimpleListener;
  12.  
  13. protected function onAddListenerClicked(event:MouseEvent):void
  14. {
  15. _listener = new SimpleListener();
  16. _listener.listen(_dispatcher);
  17. }
  18.  
  19. protected function onRunGCClicked(event:MouseEvent):void
  20. {
  21. try
  22. {
  23. new LocalConnection().connect('foo');
  24. new LocalConnection().connect('foo');
  25. }
  26. catch (e:*) {}
  27. }
  28.  
  29. protected function onDispatchClicked(event:MouseEvent):void
  30. {
  31. _dispatcher.dispatch();
  32. }
  33.  
  34. ]]>
  35. </fx:Script>
  36.  
  37. <s:VGroup width="100%" height="100%" horizontalAlign="center" verticalAlign="middle">
  38. <s:Button label="Add Listener" click="onAddListenerClicked(event)" />
  39. <s:Button label="Run GC" click="onRunGCClicked(event)" />
  40. <s:Button label="Dispatch" click="onDispatchClicked(event)" />
  41. </s:VGroup>
  42.  
  43. </s:Application>

So what I should expect to see from this example is that when I click “Add Listener” it should create a listener reference which will then listen for when the signal is dispatched and trace out a “ping”.

What actually happens is you get nothing. No trace out, despite the fact that there is clearly still a reference to the listener in the Application file.

So whats happening here? If you break into the debugger at the point that the listener is added then you get the following:

You can see that the type “MethodClosure” is added as the key to the dictionary rather than Function which is passed in. MethodClosure is a special native Flash Type that you dont have access to. It exists to resolve the issues we used to have in AS2 where passing a function of a class to a listener would cause the listener to go out of scope and other nasties. From the Adobe docs:

Event handling is simplified in ActionScript 3.0 thanks to method closures, which provide built-in event delegation. In ActionScript 2.0, a closure would not remember what object instance it was extracted from, leading to unexpected behavior when the closure was invoked.

..

This class is no longer needed because in ActionScript 3.0, a method closure will be generated when someMethod is referenced. The method closure will automatically remember its original object instance.

The only problem is that it seems that using a MethodClosure as a key in a weak dictionary causes the MethodClosure to have no references and hence be free for garbage collection as soon as its added to the Dictionary which is not good :(

So thats about as far as I got, I have spent a few evenings on this one now and I think im about ready to call it quits. I had a few ideas about creating Delegate handlers to make functions very much in the same way as was done in AS2 but then I read this post: http://blog.betabong.com/2008/09/26/weak-method-closure/ and the subsequent comments and realised it probably wasnt going to work.

I also had an idea about using the only other method of holding weak references the EventDispatcher class. I thought perhaps somehow I could get it to hold the weak references then I could loop through the listeners in there calling dispatch manually. Despite “listeners” property showing up in the Flex debugger for an EventDispatcher you dont actually have access to that property unfortunately so hence cant get access to the listening functions. Interestingly however the EventDispatcher uses “WeakMethodClosure” object instead of the “MethodClosure” object according to the debugger.

Well I guess for now Ill have to make sure I code more carefully and unlisten from my Signals ;)

Flex 4 Spark & Rollover Group Containing Rect

Was working on my top-secret Flex-based project over the weekend when I discovered something I hadn’t come across before.

The issue is that when you have a Spark Rect GraphicsElement within a Spark Group it seems that the rollover event of the group is triggered even though the mouse doesn’t roll over the Rect.

Here is a video I made to explain my issue on Twitter:

The code in the video is as follows:

<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
   xmlns:s="library://ns.adobe.com/flex/spark"
   xmlns:mx="library://ns.adobe.com/flex/mx"> 
 
	<s:Group rollOver="trace('ya')">
		<s:Rect x="100" y="100" width="20" height="20">
			<s:fill>
				<s:SolidColor color="0x00ff00" />
			</s:fill>
		</s:Rect>
	</s:Group> 
 
</s:WindowedApplication>

It turns out (after posting the issue on the Adobe Forums) that I was simply missing the “mouseEnabledWhereTransparent” property on the Group. Setting it to false causes the mouse to perform a hit-test rather than a simple bounds check. Thank you Mr Shongrunden for pointing this out to me :)

So this now works:

<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
   xmlns:s="library://ns.adobe.com/flex/spark"
   xmlns:mx="library://ns.adobe.com/flex/mx"> 
 
	<s:Group rollOver="trace('ya')" mouseEnabledWhereTransparent="false">
		<s:Rect x="100" y="100" width="20" height="20">
			<s:fill>
				<s:SolidColor color="0x00ff00" />
			</s:fill>
		</s:Rect>
	</s:Group> 
 
</s:WindowedApplication>

I hope this helps someone else out!

LieroXNA – Digging up the past..

I received a very pleasant email yesterday from a fine chap Michael Lindholm. He was enquiring about my old project LieroXNA and whether I was still working on it. As it sound like some people are still interested in the project Ill copy / pase the email for the record here:

Hi mike :)

I have read your blog several times now over the last few months(about LieroXNA) and thought i should just let you know i find your LieroXNA project very interesting :)
very impressive work with those particles aswell, very nice work :)
infact… not to long ago i was in the IRC channel #XNA and people was talking about “that XNA liero game with all the particles” so apparently you have made an impression on the world ;) hehe

but the last post seems to be from 2007, are you still working on the project?

Also, One thing that makes me very interested in Liero and XNA related projects is the fact that i am my self working on a Liero3D game in XNA, if you are interested you can find info about it here:
http://liero3d.blogspot.com/

PS: Sorry about my bad spelling (Dyslexia)

take care
/Michael

——- and my reply: ——–

Hi Mike,

Firstly its great to hear from someone who appreciates my work. Im surprised that people know about my old little project. Unfortunately it is a dead project now :(

I actually took the game to a high standard, and took it to eidos publishers in Wimbledon to see if they were interested in the game. Unfortunately, despite the backing of my employers Eidos werent interested in an XBLA game not after their other XBLA disasters. From that point on I lost heart in the project, I dont know why but I didnt want to continue it on any more.

Whats worse is I have actually lost everything! I have lost the source code and the binary everything, I cant believe my own stupidity. All I have left is a power point presentation and some screenshots :(

lieroxna1lieroxna2

The game play was actually very good fun, we played quite a few 4-man games in the office.

I may pick up the project again some point in the future, but it wont be for profit, it will be for fun.

I just checked out your 3d-liero project and I must say it looks very interesting! How are you doing the 3d destructibility? Voxels with a polygon mapping algorithm? Have you ever heard of voxlap? http://advsys.net/ken/voxlap.htm very interesting project from a while back, was very interested for a while, was thinking of woking on a voxel engine for my university, but decided against it in the end, the complexity is immense.

Well anyways, im starting to ramble, its good to see you continuing on with liero and I wish you best of luck, ill be watching with keen interest.

Mike

Well the result of this is I have been digging around and have found “some” old source code, its not complete, but over the coming weeks im going to take a look at it and see if I can get it in a state where I can post it up here, it would be a shame to let this one rot.

1 2 3 Scroll to top