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.
This article really helped. I was looking for casting objects between different object types after doing deep copy.
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….
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!
This is great info to know.
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.
Here is your answer: http://livedocs.adobe.com/flex/201/langref/mx/utils/ObjectUtil.html#copy()
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.
Thank you – just the problem I was having
registerClassAlias fixed my issue – Thanks for the post!
This info provided a quick, concise and clear answer to our problem. Thanks!
You can also use the
[RemoteClass(alias="com.path.ClassName")]
MetaData Tag in the class definition to register the alias.
Thanks for the input!
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?
brilliant. Thanks
Thanks, very usefully!