11 May 2010

Using Flash Proxy Class

According to Adobe’s Help, the Proxy class (flash.utils.Proxy) lets you override the default behavior of ActionScript operations (such as retrieving and modifying properties) on an object.

The usage note sounds interesting but this is one of the least used classes in AS3. In fact there are some use cases of this class which prove it is extremely powerful and may help you save many lines of code. Some of those are:

  • OrderedObject: an object whose properties order are strictly maintained.
  • TraversableObject: an object which allow you to traverse through its declared properties by using for loop.

First let’s see how to use it.

The Proxy Class

The Proxy class is meant to be extended. In your own class definition, you must override some special methods of Proxy class which are responsible for some object operations in AS.

They are:

Override this when you want to set property, i.e MyObject.myProperty = “something”;

override flash_proxy function setProperty(name:*, value:*): void {   }

Override this when you want to get property, i.e trace(MyObject.myProperty);

override flash_proxy function getProperty(name:*):* {   }

Override these when you need to traverse through properties with for..in or for each..in

  1. override flash_proxy function nextNameIndex (index: int): int { } 
  2. override flash_proxy function nextName(index: int): String { }
  3. override flash_proxy function nextValue(index: int): * { }

Override this when you call object’s method hasOwnProperty()

override flash_proxy function hasProperty(name: *): Boolean { }

Override this when there’s a need to delete properties with delete operator.

override flash_proxy function deleteProperty(name: *): Boolean { }

Override this if you want to use descedant (..) operator with your object. Normally, the descendant operator only available in E4X objects. One example for this operation: you want to get MyObject..myProp which will recursively traverse through the object’s properties and the properties’ properties etc. and return an array of values whose name is myProp

override flash_proxy function getDescendants(name:*): * { }

Please note:

  • Your Proxy-extended class will have no default behaviour for object operations. Flash Player will throw exceptions for any operations that are not defined by you in your custom class.
  • Most of these operations only affect dynamic properties. For example: if you have a declared member “prop”, when you get obj.prop, your object will return the value of “prop” directly and the method getProperty() is not invoked.

Let’s take a look at some use cases to understand more about Proxy.

OrderedObject  (source code)

As you may notice, when you iterate through an object with for loop, you don’t access its properties in the order you created them. For example:

var obj: Object = {a: 1, b: 2, c: 3};
obj.d = 4;
obj.e = 5;
for (var prop: String in obj) {
    trace(prop + " - " + obj[prop]); // not in order 1, 2, 3, 4, 5
}

This issue of order, most of the time, is acceptable. However, there are cases where the order of properties is very important. For example: a QueryString object which parse this string “a=1&b=2&c=3&d=4&e=5” and hold all the values in its dynamic properties. Unfortunately, when you iterate the properties list and return the string back, the output are not the same with input anymore. Imagine you use this class to work with SWFAddress, you will get 2 different URLs for the same page access (the browser will see http://yourdomain.com/?a=1&b=2&c=3&d=4&e=5 different from http://yourdomain.com/?c=3&d=4&a=1&e=5&b=2).

With OrderedObject and its extension QueryString, I can solve the above issue.

OrderedObject example:

import org.thanhtran.model.data.OrderedObject;

var obj: OrderedObject = new OrderedObject( ["a", 1, "b", 2, "c", 3] );
obj.d = 4;
obj.e = 5;
for (var prop: String in obj) {
    trace(prop + " - " + obj[prop]); //in order a – 1, b – 2, c – 3, d – 4, e – 5
}

QueryString example:

import org.thanhtran.model.data.QueryString;

var query: QueryString = new QueryString("a=1&b=2&c=3&d=4&e=5");
trace(query.toString()); //a=1&b=2&c=3&d=4&e=5
//change parameters
query.a = "one";
query.e = "five";
trace(query.toString()); //a=one&b=2&c=3&d=4&e=five

TraversableObject (source code)

Say, your project may have a few data objects (AKA value objects) which are used to transfer data among components. There a times you want to iterate through their properties list to quickly copy the values or something. However, it is impossible to use for..in and for each..in statement to iterate declared properties.

By extending TraversableObject (which is an implementation of Proxy), your object properties can now be iterated through with for loop.

Here’s how:

public class MyObject extends TraversableObject {
    public var a: String = "1";
    public var b: int = 2;
    public var c: Number = 3;

    public function MyObject() {
        //list all the public properties you want to iterate here
        //DO NOT list private or dynamic ones
        propertyList = ["a", "b", "c"];
    }
}
/* … */
var obj: MyObject = new MyObject();
for (var prop: String in obj) {
    trace(prop + " - " + obj[prop]); //in order a – 1, b – 2, c – 3
}
 

You can check out the demo FlashDevelop project here.

These are just some practical applications of Proxy class, I think there must be plenty of circumstances where this special class proves useful.

[Vietnamese tags: Sử dụng lớp Proxy của Flash: thay đổi cách truy xuất và các thao tác lên đối tượng trong ActionScript]

2 comments:

  1. Hi
    Its really helpfull.
    It saved my time.
    thanks

    ReplyDelete
  2. Thanks, this explains the proxy class quite well, been a while since i last looked into it.

    I am gonne use to create some none flex bindable properties for MVC use :)

    ReplyDelete