Archive for the 'Flex' Category
Quick Reference: Method Closures From The Ground Up
Although for the most part I understood what method closures were all about, if you had asked me to define exactly what one was, I previously would have stumbled, so I thought I'd solidify my knowledge a little by writing a quick post - I'll keep it as short as possible!
Functions vs Methods
Just to make sure we're all on the same page, you should know the difference between a function and a method: at its most basic, a function is a block of code that you can execute, and a method is just a function which belongs to an object. So, if I called ball.bounce() I would be calling the bounce method of the ball instance (bounce is a function, and is also a method of the ball instance).
Named vs Anonymous Functions
We can have named functions & anonymous functions. Those of you who have experience with AS2 may be more familiar with anonymous functions than those who don't.
-
//named function (it has the name 'sayHello')
-
function sayHello():void{
-
trace("Hello!");
-
}
-
-
//anonymous function (function without a name)
-
function():void{
-
trace("Hello!");
-
}
-
-
//Example of using an anonymous function, AS2 stylie!
-
//The anon function is only called when the user clicks button1
-
button1.onClick = function(){
-
trace("button was clicked");
-
}
'this' keyword
If we're going to talk about method closures and scope, we should discuss 'this'. Even though it won't apply to my final example, it is important to understand.
Because I want to keep this post simple, I will just talk about how it behaves in AS3. What 'this' refers to, differs, depending upon whether or not you are using an anonymous or named function.
In AS3 if you use a named function, 'this' will always refer to the original context of the function definition (ie to the object on which you initially defined that function). Therefore, if you defined your named function on the main timeline of a Flash movie, 'this' would always refer to the root of that movie, and if you defined your named function within an instance of a class, 'this' would refer to that class instance.
-
//All of this code sits inside an instance of a class named 'myBall' ...
-
-
function sayHello():void{
-
trace(this + ' says hello');
-
}
-
-
var obj1:Object = new Object();
-
obj1.sayHello = sayHello;
-
-
var obj2:Object = new Object();
-
obj2.sayHello = sayHello;
-
-
obj1.sayHello();//will trace "myBall says hello"
-
obj2.sayHello();//will trace "myBall says hello"
Anonymous functions act slightly differently. In this case it is 'the object from which the function is being called' that is represented by 'this'. That may sound confusing so let me show you an example:
-
var obj1:Object = new Object();
-
obj1.sayHello = function(){
-
trace(this + ' says hello');
-
}
-
-
var obj2:Object = new Object();
-
obj2.sayHello = obj1.sayHello; //note what I'm doing here!
-
-
obj1.sayHello();//in theory this should trace "obj1 says hello"
-
obj2.sayHello();//in theory this should trace "obj2 says hello"
The code above says "in theory this should trace ..."
Both calls would actually trace out [Object object] says hello because we are just creating instance of an Object. That's not very useful. If we wanted to get a better trace we could give each object a 'name' property:
obj1.name = "obj1";
obj2.name = "obj2";
then we would change our anonymous function to say:
trace(this.name + ' says hello');
What is important to note is that in the second instance, even though I assign obj1.sayHello to obj2.sayHello, 'this' still refers to obj2!
Now let's define a couple of things and finish off by giving one last example which should illustrate the concept of method closures.
Lexical Environment (definition)
Big phrase, simple meaning: The lexical environment includes all the variables, properties, methods, and objects in the function's scope chain, along with their values.
Why did you need to know that? Because it simplifies the definition of what a function closure is ...
Function Closure (definition)
A function closure is an object that contains a snapshot of a function and its lexical environment.
Function closures retain the scope in which they were defined (remember what we said earlier when discussing 'this'?). Hopefully the final example should solidify your understanding.
Example of a Function Closure
We're going to create a named function which returns an anonymous function. The point of this is to show that the anonymous function has access to any arguments (and/or local variables) which were defined (or sent in to) in the named function. The anonymous function still has access to these arguments/variables even after the named function has finished executing! We say it 'runs in the scope of the named function'.
-
/**
-
* The body of the inner function (anonymous) is not executed at the same time as
-
* the outer function ('generator'). However, the inner function has access to the
-
* outer function's argument (num1), because it is shares the same
-
*scope as the outer function.
-
*/
-
public function generator(num1:Number):Function
-
{
-
return function(num2:Number):Number //function closure defined
-
{
-
return num1 + num2;
-
};
-
}
-
-
//called when Flex's creationComplete event fires...
-
public function onCreationComplete():void
-
{
-
//create a new function which will accept an argument
-
//& always add 10 to that argument
-
var addTen:Function = generator(10);
-
trace( addTen(5) ); //traces 15
-
}
Okay, so the first time you look at this example it's fair enough to think "Erm that's confusing!" I'm sure you wouldn't be alone in that, so let's just step through it and I'll try to explain what's going on ...
Whenever we call 'generator' we need to send in a number ('generator' is a named function that accepts an argument). 'Generator' will create and return an anonymous function, and because the anonymous function is created in the scope of 'generator' this anonymous function will have access to the argument we sent in. It continues to have access to it, even after 'generator' has finished executing!
So, when do we do this? In the above example we do it upon creationComplete: we create a function called 'addTen' (we call 'generator', sending in the number 10), and that returns our anonymous function, which, remember, has access to the number 10.
var addTen:Function = generator(10);
This number (10) is the num1 that we refer to in our 'generator' function.
When we eventually run 'addTen', it expects a parameter (this is the num2 that we refer to in our 'generator' function). We send in the parameter, which can be any number (here we send in 5), and it adds that number to 10.
... in other words, our anonymous function 'remembers' the number 10, even though the 'generator' function into which we sent 10 has already returned.
So What Is A Closure Again?
A closure is formed when an inner function is made accessible outside of the function in which it was contained. It still has access to the arguments and local variables of its outer function, and can be executed after the outer function has returned.
No comments
Flash Debug Player Causing Firefox Crashes – A Fix
Problem
If you've updated to a recent version of Firefox and also use the Flash Debug Player to debug Flash & Flex apps, you may already be painfully aware of the recent changes to the way Firefox 3.6.6 handles its plugins.
Now, rather than simply alerting you, letting you dismiss the error and continue on your merry way, Firefox takes control and kills the process for you because it detects that something is wrong. This completely disables the plugin and prevents you from debugging your app (while making you hang around for 45 seconds, just to infuriate you that little bit more) ;]
This also causes a problem during general day-to-day surfing because any site that doesn't handle errors properly and/or throws null objects ( ... yeah channel4.com I'm looking at you!) will also result in your Flash plugin being disabled.
Solution
You need to go in to the Firefox config settings (type about:config in to the location bar) and search for dom.ipc.plugins.enabled.npswf32.dll - double click that to set it to false. You may also need to set dom.ipc.plugins.timeoutSecs to -1. Now restart your browser and you should once again be able to debug your apps and dismiss the warnings as you used to do in the good old days. Ahhhhh bliss.
More info here.
3 comments
Using ‘Proxy’ For Loading & Accessing Config Files
Configuration Files
Externalising some of your application's settings in to config files is something most (hopefully all) of us do when writing Flex & AIR apps. It becomes almost essential when writing apps that may be moved around (e.g. say your place of work has a development server, a UAT/staging server and a production server - you don't want to have to recompile your app each time you move from one server to the other ... which is what you'd have to do if your application had things like URLs hardcoded in to them).
If you don't yet use config files, consider how they would work given the above situation.
On our DEV server we'd have a file called 'config.xml', on our UAT server we'd have a file called 'config.xml', and on our PROD server we'd have a file called 'config.xml' too. Each file would contain settings specific to that particular environment. EG:
//IN DEV CONFIG <prop id="remotingEndpoint" value="http://localhost/weborb30/weborb.aspx"/> //IN PROD CONFIG <prop id="remotingEndpoint" value="http:/mycompanywebsite.com/services/weborb.aspx"/>
In our Flex app we would do the same thing regardless:
//IN OUR FLEX APP (not showing full tag here, but you get the idea)
<mx:RemoteObject
destination="GenericDestination"
endpoint="{appSettings.remotingEndpoint}"/>
The key point is that the Flex app doesn't have to be recompiled when it is moved from server to server - it just picks up the local config settings for each environment.
A Common Approach To Creating/Loading Configs
One way people deal with config files is to create a class which loads in some settings file, usually as XML. This class most likely defines properties which correspond to the properties in the XML - the idea being that you populate the class properties from the XML properties. There are more efficient variations on this approach, but doing it that way is common - I was prompted to write this post after seeing someone doing just this. It has several drawbacks though. For example, each time you add a property to your XML you have to add that property (or getter method) to your class as well. You also end up having one class per config file, so it's not particularly reusable.
The flash.utils.Proxy Approach To Creating/Loading Configs
What would be nice is if we had an easy way to load in our config XML file and have all the properties instantly available via our class. This is where flash.utils.Proxy comes in. There are four things we need to do in order to get this to work (five if we want our class to dispatch events as well):
- Make our class dynamic
- Extend flash.utils.Proxy
- Override its 'getProperty' method
- Use the flash_proxy namespace (in order to be able to override getProperty)
- (optional) Implement IEventDispatcher
I'll go over the key points now but it's easier to see it in action so I would recommend downloading this example file ( in FlexBuilder choose file->import->existing projects in to workspace ... select 'archive file' and browse to the file you downloaded).
(1) Our class is declared using the dynamic keyword - essentially this allows other classes to request any properties from it, at runtime, and errors won't be generated even if the property doesn't exist. So we could ask for myinstance.thisVariableDoentExist and no error would be thrown.
(2) Next we extend flash.utils.Proxy because we want a way to capture these undefined property requests; With flash.utils.Proxy, when such a request occurs, a method of the Proxy class called getProperty() is automatically triggered for us (there are other methods triggered by other actions, so be sure to check out the docs - this is one handy class), and this allows us to do something in response to that request.
(3) We override the getProperty() method, so that we can write code which responds to the undefined requests.
(4) One small quirk is that the getProperty() method exists inside the flash_proxy namespace; All this means for us is that we have to import flash.utils.flash_proxy (intellisense won't pick it up, but it does exist) and use it in front of the method (much in the same way we use access modifiers like 'public' and 'private') - see the code for an example.
(5) Our class also needs to load in some XML (our external config file), store it, and optionally dispatch an event once the data has loaded in, which is why I also implement the IEventDispatcher interface - if you're not familiar with implementing IEventDispacher I suggest you look it up in the docs because about half the code in this class can essentially be ignored if you don't want to dispatch events. We can't extend multiple classes in AS3 - we are already extending Proxy, so we have to implement IEventDispatcher rather than extend EventDispatcher in order to get event dispatching functionality.
Putting It All Together
Okay, now that we can store XML and catch undefined property requests, we can see what property is being requested and look for it inside our loaded XML file. We return the value being requested, from the XML, but it appears as if the property belongs to our class. As the name implies, we are proxying the request on to the XML.
Below is a snippet of our class. You can see that in getProperty() I use e4x to grab the value out of the saved XML file. If the XML doesn't contain the value then our method returns an empty String (of course you can modify this how you see fit):
package config
{
/**
* config.AppConfig.
*
* Loads & stores an XML config file, and returns the data from it as if the data belonged to the class instance.
* XML data nodes must be in the form:
*
(where nodeID & nodeValue represent your values).
*
* NOTE: Class is dynamic.
* Class overrides Proxy.
* Class imports & uses flash_proxy namespace.
*
*/
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
import flash.events.IOErrorEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.utils.Proxy;
import flash.utils.flash_proxy;
public dynamic class AppConfig extends Proxy implements IEventDispatcher
{
protected var _eventDispatcher:IEventDispatcher;
protected var _data:XML;
protected var _dataLoaded:Boolean = false;
private var _urlLoader:URLLoader;
public function AppConfig()
{
_eventDispatcher = new EventDispatcher();
}
public function loadConfigFile(url:String):void
{
var request:URLRequest = new URLRequest(url);
_urlLoader = new URLLoader();
_urlLoader.addEventListener(Event.COMPLETE, onDataLoaded);
_urlLoader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
_urlLoader.load(request);
}
protected function onDataLoaded(event:Event):void
{
_data = XML(_urlLoader.data);
_dataLoaded = true;
removeListeners();
dispatchEvent(new Event(Event.COMPLETE));
}
override flash_proxy function getProperty(name:*):*
{
if(_data)
{
var propName:String = name.toString();
return (_data.prop.(@id == propName).@value).toString();
}
}
//.....more class stuff not shown
So the upshot is that we now have a class that can load in any config file (as long as the XML follows the same formatting), and this class doesn't have to be updated if/when the XML changes. We can instantiate n instances of our class and load in n types of XML file (one for config settings, one for strings, one for whatever else we need). It's a handy way to approach the loading of config files.
9 comments