Easy deep clone method made easier
Posted by Dennis on Feb 19, 2009 in ActionScript, Flash, Flex • 9 commentsIn a previous post I talked about an easy deep cloning method I found and which I tweaked a little.
While I was crammed in the tube yesterday (sometimes the best ideas are born in the underground) I came up with an idea to simplify and generalise this even further. The problem with the current method lies within the call to registerClassAlias(). This call contains two values that are specific to the class:
- a hardcoded fully qualified clas name
- a reference to the current class
In order to support inheritance and to make refactoring a lot easier, we can use the getQualifiedClassName() and getDefinitionByName() methods. The new version of the clone() method:
public function clone() : MyClass
{
var qualifiedClassName : String = getQualifiedClassName( this ).replace( "::", "." );
var bytes : ByteArray = new ByteArray();
registerClassAlias( qualifiedClassName, getDefinitionByName( qualifiedClassName ) as Class );
bytes.writeObject( this );
bytes.position = 0;
return bytes.readObject() as MyClass;
}
Let’s see if this works when we use inheritance. This is the class that defines the clone() method:
package com.rozengain.cloning
{
import flash.net.registerClassAlias;
import flash.utils.ByteArray;
import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;
public class MyClass
{
public var property1 : String;
public var property2 : Array;
public function clone() : MyClass
{
var qualifiedClassName : String = getQualifiedClassName( this ).replace( "::", "." );
var bytes : ByteArray = new ByteArray();
registerClassAlias( qualifiedClassName, getDefinitionByName( qualifiedClassName ) as Class );
bytes.writeObject( this );
bytes.position = 0;
return bytes.readObject() as MyClass;
}
}
}
This is the subclass that inherits the clone() method:
package com.rozengain.cloning
{
public class MyClassNew extends MyClass
{
public var property3 : String;
public function MyClassNew()
{
super();
}
}
}
In the main application class we execute this bit of code:
var myClass : MyClassNew = new MyClassNew();
// -- property3 is a property specific to MyClassNew, MyClass doesn't have it
myClass.property3 = "foo";
var myClone : MyClassNew = myClass.clone() as MyClassNew;
trace( myClone.property3 );
… and the output is as we expect it to be … “foo”.
The cast is very important:
var myClone : MyClassNew = myClass.clone() as MyClassNew;
If you omit that it will throw an error in your face.

Is this an expensive clone. I understand it is related to the size of the object being cloned, but I was wondering if you did some test?
Jiri
Hey Jiri,
Good question. I haven’t tested the performance yet, but I will do soon
Thanks
Dennis
fucking genius!
So far any test results?
hi.. uhm.. admin
what if one of your member properties are of a non-primitive type, or lets say of a second custom class? guess it fails due to the fact that it doesn’t really _deep_ clone?
hehe now i thought about it for several minutes and got nothing productive to say. so i’ll just submit this mean comment.
@kris, I tested this morning with ClassB and ClassC custom class properties of my ClassA custom class. After cloning an instance of ClassA with the method above, I traced the qualifiedClassName of the clone’s ClassB and ClassC properties. The traces successfully reported “com.x.y.z.ClassB” and “com.x.y.z.ClassC”. At least in the case of this example it _seems_ like custom class properties of the cloned class object instance do retain their class identities.
Hi there, I’m very new to Actionscript and Flex and was wondering how you would use this example to clone an element and then add it as a child to a container in Flex? For example, I have a Flex4 group with some Graphic elements inside it, such as an
How would I use this method to clone the ellipse graphic and add it as a child to the Group container that its source lives in?
Thanks much.
This solution has one downside. Is is very generic but if you have typed objects inside the parent object, they will be null. So in order to overcome this, each object should have a custom clone method.
For recursive cloning register all the other class aliases you have inside the parent object:
registerClassAlias( “com.rozengain.cloning
.MyClass2″, getDefinitionByName( “com.rozengain.cloning
.MyClass2″ ) as Class );
registerClassAlias( “com.rozengain.cloning
.MyClass3″, getDefinitionByName( “com.rozengain.cloning
.MyClass3″ ) as Class );
it will work with Arrays of typed objects as well.
Also to make it more generic, you should also add this:
var qualifiedClassName : String = getQualifiedClassName( new TestScore() ).replace( “::”, “.” );
registerClassAlias( qualifiedClassName, getDefinitionByName( qualifiedClassName ) as Class );
the solution i posted above will have problems if you rename the class or move the class.