Type Casting and ObjectUtil.copy(obj) in ActionScript 3.0

When programming in Object Oriented Languages, in this case ActionScript 3.0, having different copies of the same object is sometimes a common need.
For many, the most obvious approach would be to simply assign one object to another, like this:

myObj2 = myObj1;

But this approach would not copy the objects. Instead this approach would only copy the object references. In the end there will be only one object, which would be referenced from two places, meaning that changing myObj1 is the same as changing myObj2 and vice-versa.
By the way, in Flex everything is a reference!

The question is how do we clone an object in ActionScript 3.0?

ActionScript 3.0 has several utility functions, and one of them is the ObjectUtil.copy(Obj) which can be found in the package mx.utils;

This function will perform a deep copy of the object that is given as argument. And this is done by using the built in flash player AMF capabilities (yes, in Flex you will find really odd and original solutions for problems). What happens here is that the entire object is serialized into an array of bytes, and when the bytes are deserialized, a brand new object is created copying all of the original contents.
Still, you won’t be able to type cast most of the resulting objects (in fact, only primitive types can be type casted). And this is because when an object is deserialized from AMF, although it haves all the properties of a class instance, it will not be a true class instance nor will hold any references to the original class.
This is solved by adding type information about the object to the AMF packet. This can be done by using the registerClassAlias()
method which is available in the flash.net package. This method will allow to preserve the class (type) of an object when the object is encoded in Action Message Format (AMF).

Let’s take a look to the following source code:

Sample code A:

public var myObj:MyObject = new MyObject();
myObj.someProperty = “myProperty”;

public var myObjCopy:Object = ObjectUtil.copy(myObj);
trace(myObj.someProperty): // “myProperty”
trace(myObjCopy.someProperty): // “myProperty”
myObjCopy.someProperty = “myChangedProperty”;
trace(myObj.someProperty); // “myProperty”
trace(myObjCopy.someProperty); // “myChangedProperty”

Sample code B:

public var myObj:MyObject = new MyObject();
myObj.someProperty = “myProperty”;
public var myObjCopy:MyObject = ObjectUtil.copy(myObj) as MyObject;
trace(myObj.someProperty): // “myProperty”
trace(myObjCopy.someProperty);

//FAULT: cannot access object with null reference.
//Execution stops!

Sample code C:

public var myObj:MyObject = new MyObject();
myObj.someProperty = “myProperty”;
registerClassAlias("my.package.myObject",MyObject);
public var myObjCopy:MyObject = ObjectUtil.copy(myObj) as MyObject;
trace(myObj.someProperty):   // “myProperty”
trace(myObjCopy.someProperty):  // “myProperty”
myObjCopy.someProperty = “myChangedProperty”;
trace(myObj.someProperty);  // “myProperty”
trace(myObjCopy.someProperty); // “myChangedProperty”

Why does it work on A and C and not on B?

Well, in A it works because we are using the type Object. And it would also for other primitive types such as Array.
In C it works because we are passing (registerClassAlias) the object type before it gets encoded, which will result in a successful type cast.
In B we don’t preserve the objects type, meaning that after the object gets deserialized it will hold no references to the MyObject class. The result will be a failed type cast which will result in pointing out to a null object reference.

But… ObjectUtil.copy(obj) it’s not bullet proof. I will not address to this situation because Darron schall has already a great post on this issue.

About these ads

15 Responses to “Type Casting and ObjectUtil.copy(obj) in ActionScript 3.0”


  1. 1 Piyush Sacheti July 6, 2008 at 2:30 pm

    This article really helped. I was looking for casting objects between different object types after doing deep copy.

  2. 2 walter August 21, 2008 at 8:43 am

    i have a quite complex custom class ( with arrays of other classes as members, etc) and somehow the copying of the object does not work. i get no compile errros, but the properties of the copied object are all null.

    hmmmmm….

  3. 3 Lucas Pereira September 16, 2008 at 6:16 pm

    Well, once i wan into that problem…

    My Solution was to register all the objects that made my “big” object…

    Something like this:

    registerClassAlias(“my.package.myInnerObject1″,MyInnerObject1);
    registerClassAlias(“my.package.myInnerObject2″,MyInnerObject2);
    registerClassAlias(“my.package.myBIGObject”,MyBIGObject);

    If i can remember it worked… But only for some of the “InnerObjects”!

    Still this is a pretty “ugly” approach… image i’d had 20 inner Objects…

    Still… If I had 20 inner Objects I think I would need some refactoring…

    Anyways, it took me so long to answer this, that probably you already have the best solution…

    If so give me a hint!

  4. 4 Quinta November 11, 2008 at 12:13 pm

    This is great info to know.

  5. 5 james January 5, 2009 at 11:56 pm

    Is this also works on UI components? I want to copy a label on the first canvas of my viewstack to the second canvas. I tried using registeredClassAlias but doesn’t work for me.

  6. 7 james January 7, 2009 at 12:39 am

    I can’t still typecast the object to Label. I decided just to dynamically create the labels in both canvases, so I wouldn’t be performing any copy. This is the best turnaround I can think off, besides I will also need to dynamically create other unique labels too. I am doing a report.

  7. 8 Martin Harrigan April 17, 2009 at 7:42 pm

    Thank you – just the problem I was having ;-)

  8. 9 Sam July 21, 2010 at 2:28 pm

    registerClassAlias fixed my issue – Thanks for the post!

  9. 10 Agota August 3, 2010 at 11:19 am

    This info provided a quick, concise and clear answer to our problem. Thanks!

  10. 11 David September 19, 2010 at 12:39 pm

    You can also use the

    [RemoteClass(alias="com.path.ClassName")]

    MetaData Tag in the class definition to register the alias.

  11. 13 Andrea Mirò March 22, 2011 at 8:27 pm

    Hi Lucas,
    I have this problem as well.
    I’ve got an array full of objects instances of a class of mine called Card and I want to copy it entirely.

    When I use the ObjectUtil.copy() I’ve got an Array full Objects and I can’t use my array.sort(myFunc).

    When I use your method like this:
    registerClassAlias(“gameCore.Card”,Card);
    var tempHand:Array = ObjectUtil.copy(hand) as Array;

    I get this error:
    ArgumentError: Error #1063: Argument count mismatch on gameCore::Card(). Expected 3, got 0
    at flash.utils::ByteArray/readObject()
    at mx.utils::ObjectUtil$/copy()[E:\Programmi\Adobe\Adobe Flash Builder 4\sdks\4.1.0\frameworks\projects\framework\src\mx\utils\ObjectUtil.as:122]

    how can I fix?

  12. 14 frank May 23, 2011 at 11:14 pm

    brilliant. Thanks

  13. 15 Max October 25, 2011 at 12:42 pm

    Thanks, very usefully!


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s





Follow

Get every new post delivered to your Inbox.

%d bloggers like this: