Dictionary Class in AS3

When was the last time you used the Dictionary? No, seriously, when was the last time???

[as3]
var dictionary:Dictionary = new Dictionary();
[/as3]

Perhaps one of the most interesting additions to the ActionScript 3 language is the new Dictionary Object. It provides a quick and absolute mechanism for looking up values based on object keys. Much to the same way Array elements are associated by numeric indexes and Objects by string key names, Dictionary elements are associated by the instance of an object.

Associative Lists

[as3]
// Arrays use numeric indexes
var array:Array = new Array();
array[0] = “value”;

// Objects use string indexes
var object:Object = new Object();
object[“key”] = “value”;
//Same as…
object.key = “value”;

// Dictionary uses object keys
var dictionary:Dictionary = new Dictionary();
dictionary[object] = “value”;
[/as3]

Non-Primitive Identifiers

The real beauty of the Dictionary object lies in its effortless and dynamic way of referencing non-primitive objects or custom classes, absolutely. By absolutely, I mean it uses the object’s identity or instance to match up the object, it uses the strict equality (===) for comparison.

[as3]
var dictionary:Dictionary = new Dictionary();
var button:SimpleButton = new SimpleButton();
dictionary[button] = “BUTTON”;

trace(dictionary[button] == “BUTTON”);
//Outputs true because dictionary[button] === “BUTTON”
[/as3]

Primitive Identifiers

On the other hand, primitive or built-in objects, like Numbers, Strings… in a Dictionary collection will act the same way as they would say in an Array [], or a generic Object {} as primitives don’t have new instances and their property or value is returned.

[as3]
//String example
var dictionary:Dictionary = new Dictionary();
dictionary[“a”] = “b”;
trace(dictionary[“a”]); //Outputs “b” because “a”===”b”

//Number example
dictionary[123] = 456;
trace(dictionary[123]); //Outputs 456 because 123===456
[/as3]

It’s also worth noting that the Dictionary object matches based on the instance of the object, not the reference of the object. So, this opens up the possibility for multiple references to the same object with the same key.

[as3]
var a:Object = new Object();
var b:Object = a;
var dictionary:Dictionary = new Dictionary();
dictionary[a] = “abc”;
trace(dictionary[b]); //Outputs ‘abc’ because a===b
[/as3]

Weak Keys

Another feature that sets the Dictionary object apart from an Array or Vector is its ability to hold weak references to its collection. By passing a true to the first and only parameter of the Dictionary object, it will release the object to the garbage collector, of course when all references have been cleared for that object. If you were using an Array or Vector, you would also need to remove the reference from the list whereas the Dictionary will remove it from the collection automatically…

[as3]
var dictionary:Dictionary = new Dictionary(true);
var a:Sprite = new Sprite();

dictionary[a] = new Object();
trace(dictionary[a]); //Outputs [object Object]

a = null; //Clear reference to the Sprite.

trace(dictionary[a]); //Outputs undefined
[/as3]

There are a whole host of applications for the Dictionary Class. I have found it most useful keeping track of form UI elements, namely buttons. It comes in very handy when writing form validation systems or even MouseEvent.CLICK listening for many buttons on a single form. The code below illustrates a scenario where you might have many buttons on a page and instead of having separate event handlers for each instance, you can listen to a container and catch the events on the bubble phase.

Example Application

[as3]
//consts of directions
const TOP:String = “TOP”;
const RIGHT:String = “RIGHT”;
const BOTTOM:String = “BOTTOM”;
const LEFT:String = “LEFT”;

//simply clickable entities
var buttonTop:SimpleButton = randomButton();
var buttonRight:SimpleButton = randomButton();
var buttonBottom:SimpleButton = randomButton();
var buttonLeft:SimpleButton = randomButton();

//movable entity
var ball:Shape = new Shape();

//dictionary key/value pairs
var buttons:Dictionary = new Dictionary();
initButton(buttonTop, TOP);
initButton(buttonRight, RIGHT);
initButton(buttonBottom, BOTTOM);
initButton(buttonLeft, LEFT);

function initView():void
{
var buttonsClip:Sprite = new Sprite();
var ball:Shape = randomBall();
addChild(buttonsClip);
addChild(ball);
for (var button:* in buttons)
{
button.x = buttonsClip.numChildren*(button.width+5);
buttonsClip.addChild(button);
}
//listening to the container clip instead of each individual instance
buttonsClip.addEventListener(MouseEvent.CLICK, onButtonClick, true);
}

function randomBall():Shape
{
with (ball)
{
graphics.beginFill(randomNumber() * 0xFFFFFF);
graphics.drawCircle(0, 0, randomNumber() * 25);
graphics.endFill();
}
ball.x = randomNumber() * stage.stageWidth;
ball.y = randomNumber() * stage.stageHeight;

return ball;
}

function randomButton():SimpleButton
{
return new SimpleButton(buttonState(), buttonState(), buttonState(), buttonState());
}

function buttonState():Sprite
{
var state:Sprite = new Sprite();
with (state)
{
graphics.beginFill(randomNumber() * 0xFFFFFF);
graphics.drawRect(0, 0, 33, 22);
graphics.endFill();
}
return state;
}

function initButton(button:SimpleButton, direction:String):void
{
//dynamically creating the collection
buttons[button] = direction;
}

function onButtonClick(event:MouseEvent):void
{
if (event.target is SimpleButton)
moveObject(buttons[event.target]);
}

function moveObject(direction:String):void
{
trace(“moveObject: ” + direction);

var amount:uint = 5;

switch (direction)
{
case TOP:
ball.y -= amount;
break;
case RIGHT:
ball.x += amount;
break;
case BOTTOM:
ball.y += amount;
break;
case LEFT:
ball.x -= amount;
break;
}
}

function randomNumber():Number
{
return Math.random();
}

initView();
[/as3]

This entry was posted in Flash AS3, Syntax and tagged , , , , , , . Bookmark the permalink.