今天,在做一个的项目。遇到Vector的深复制,发现复制竟然不成功。(Vector里边存储的复杂数据MovieClip)。今天先记录这里,下次再研究。在想办法解决ing。 下边先进行些简单的测试。然后,用网上的方法测试。先看code:

 

package
{
    import flash.display.MovieClip;
    import flash.display.Sprite;
    import flash.utils.ByteArray;
    
    public class ArrayCopy extends Sprite
    {
        public function ArrayCopy()
        {
            var a:Array = [1 , 2 , 3];
            var b:Array = a;
            a.splice(0);
            trace("1_1  a:"+ a , "b:" + b);
            //输出:1_1  a: b:
            
            b = [];
            a = [1 , 2 , 3];
            b = a;
            b.splice(0);
            trace("1_2  a:"+ a , "b:" + b);
            //输出: 1_2  a: b:
            
            b = [];
            a = [1 , 2 , 3];
            b = a;
            a[0] = 2;
            trace("1_3  a:"+ a , "b:" + b);
            //输出:1_3  a:2,2,3 b:2,2,3

            /*                       
            通过以上的测试,能够知道,数组间的直接赋值,改变了任意一个数组里边的元素,
另外一个也会改变。无论数据是基元数据类型还是复杂数据类型
*/ b = []; a = [1,2,3]; b = a.slice(); a.splice(0); trace("2 a:"+ a , "b:" + b); //输出:2 a: b:1,2,3 b = []; a = [1,2,3]; b = a.concat(); a.splice(0); trace("3 a:"+ a , "b:" + b); //输出:3 a: b:1,2,3 b = []; a = [1,2,3]; for each(var i:int in a) { b.push(i); } a.splice(0); trace("4 a:"+ a , "b:" + b); //输出:4 a: b:1,2,3 /* 通过以上的测试,能够知道,基元数据类型的浅复制,改变了一个数组,另外一个数组不会改变
*/ b = []; a = [ 1 , "vini" , true]; b = a.slice(); a[0] = "gg" ; a[1] = 2; a[2] = false; trace("5 a:"+ a , "b:" + b); //输出:5 a:gg,2,false b:1,vini,true b= []; a = [1 , [1 , 2],3]; b = a.slice(); a[1] = [100,200]; trace("6 a:"+ a , "b:" + b); //输出:6 a:1,100,200,3 b:1,1,2,3 b= []; a = [1 , {a:1,b:2},3]; b = a.slice(); a[1].a = 100; a[1].b = 200; trace("7 a:"+ a[1].a , "b:" + b[1].a); //输出:7 a:100 b:100 /* 通过以上的测试,能够知道,基元数据类型的浅复制,改变了一个数组,
另外一个数组不会改变(如果是Array其内层值也是基元数据类型),
复杂数据类型则会改变
*/ b= []; a = [1 , {a:1,b:2},3]; var byteArray:ByteArray = new ByteArray(); byteArray.writeObject(a); byteArray.position = 0; b = byteArray.readObject(); a[1].a = 100; a[1].b = 200; trace("8 a:"+ a[1].a , "b:" + b[1].a); //输出 8 a:100 b:1 b= []; var mc:MovieClip = new MovieClip(); mc.id = 5; a = [1 , mc , 3]; byteArray = new ByteArray(); byteArray.writeObject(a); byteArray.position = 0; b = byteArray.readObject(); (a[1] as MovieClip).id = 500; trace("9 a:"+ a[1] , "b:" + b[1]); //输出 9 a:[object MovieClip] b:undefined /* 通过以上的测试,能够知道,数据的深复制,像MovieClip这样的复杂数据,
不能深复制成功,object里边如果是基元数据,可以深复制成功
*/

       var roll:Roll = new Roll(); roll.id = 5; b = []; a = [1 , roll , 3]; byteArray = new ByteArray(); byteArray.writeObject(a); byteArray.position = 0; b = byteArray.readObject(); roll.id = 500; trace("10 a:"+ a[1].id , "b:" + b[1].id , "b:" + b[1].mc); //输出 10  a:500 b:5 b:undefined /* 通过以上的测试,能够知道,普通的类可以深复制,像MovieClip这样的复杂数据,
不能深复制成功。
*/ } } }

 

package com.vini123
{
    import flash.display.MovieClip;

    public class Roll
    {
        private var _id:int = 0;
        private var _mc:MovieClip;
        
        public function Roll()
        {
            _mc = new MovieClip();
        }

        public function get id():int
        {
            return _id;
        }

        public function set id(value:int):void
        {
            _id = value;
            _mc.id = _id;
        }
        
        public function get mc():MovieClip
        {
            return _mc;
        }
    }
}

 

然后,如果Roll里边有Point,自定义类等呢。于是,找到了registerClassAlias。哎,平时没遇到,也没一个一个去阅读官方API,很多API都很陌生。像这些顶级API以前竟然没用过。

registerClassAlias(aliasName:String, classObject:Class):void
当以 Action Message Format (AMF) 对一个对象进行编码时,保留该对象的类(类型)。

语言版本: ActionScript 3.0
运行时版本: AIR 1.0, Flash Player 9, Flash Lite 4
当以 Action Message Format (AMF) 对一个对象进行编码时,保留该对象的类(类型)。将对象编码为 AMF 时,该函数将保存该对象的类的别名,以便在解码对象时可以恢复该类。如果编码上下文没有为对象的类注册别名,该对象将被编码为一个匿名对象。同样,如果解码上下文注册了不同的别名,将为解码后的数据创建一个匿名对象。

LocalConnection、ByteArray、SharedObject、NetConnection 及 NetStream 均为将对象编码为 AMF 的类的示例。

编码和解码上下文不必对别名使用相同的类。它们可以主动地改变类,条件是目标类包含源类序列化的所有成员。

参数

aliasName:String — 要使用的别名。

classObject:Class — 与给定别名相关联的类。

registerClassAlias在利用AMF3进行序列话网络通讯中,是非常有用的。需要把客户端的对象直接传送到服务器得时候,保留该对象的类(类型)。 这样的话,就可以传送自定义对象或者系统自带对象。
readObject方法对构造器有参数的类,是会出错的,会弹出参数数量不匹配这个错误。因为还原对象进行反射的时候,是默认没有参数的给构造器的。这也是有些人 讨论Sprite等对象不能进行深度拷贝的原因。所以在使用AMF3进行序列话的时候要注意这个了,还有一个就是,如果那个类包含了多个类,也就是个复合类,那么里面的那个复合类,也必须进行registerClassAlias

于是,修改了代码,参考网上的。对深复制进行试验。

1.显示对象是可以深复制的。如果这样,将颠覆以前所说的显示对象不能深复制的问题。先贴出代码吧。

文档类:Main.as

package com.vini123
{
    import com.vini123.source.Roll;
    import com.vini123.utils.ObjectUtils;
    
    import flash.display.Sprite;
    
    public class Main extends Sprite
    {
        public function Main()
        {
            var roll:Roll = new Roll();
            var otherRoll:Roll 
            roll.id = 200;
            roll.point.y = 1;

            otherRoll = ObjectUtils.clone(roll);
            
            roll.id = 100;
            roll.point.x = 100;
            roll.point.y = 100;
            roll.sky.height = 100;
            
            
            trace("roll:" , roll.id , roll.point, roll.mc.id , roll.sky.height);
            trace("otherRoll:" , otherRoll.id , otherRoll.point , otherRoll.mc.id , otherRoll.sky.height);
            
            addChild(otherRoll.mc);
            
            otherRoll.mc.x = stage.stageWidth * 0.5 -40;
            otherRoll.mc.y = stage.stageHeight * 0.5;
            
            addChild(roll.mc);
            roll.mc.x = otherRoll.mc.x + 80;
            roll.mc.y = otherRoll.mc.y;
        }
    }
}

 

Roll.as 类:

package com.vini123.source
{
    import flash.display.MovieClip;
    import flash.geom.Point;
    
    public class Roll
    {
        private var _id:int = 0;
        private var _mc:MovieClip;
        private var _point:Point;
        private var _sky:Sky;
        
        public function Roll()
        {
            _mc = new MovieClip();
            _point  = new Point();
            _sky = new Sky();
            
            doGraphics();
        }

        public function get id():int
        {
            return _id;
        }

        public function set id(value:int):void
        {
            _id = value;
            _mc.id = _id;
            _point.x = _id;
            _point.y = _id;
            sky.height = _id;
        }
        
        public function get mc():MovieClip
        {
            return _mc;
        }

        public function get point():Point
        {
            return _point;
        }
        
        public function get sky():Sky
        {
            return _sky;
        }
        
        private function doGraphics():void
        {
            _mc.graphics.beginFill(0x0ff,0.36);
            mc.graphics.lineStyle(1,0xff0,0.6);
            _mc.graphics.drawCircle(0,0,180);
            _mc.graphics.endFill();
        }
    }
}

 

Sky.as 类:

package com.vini123.source
{
    public class Sky
    {
        private var _height:int = 0;
        public function Sky()
        {
            
        }
        
        public function get height():int
        {
            return _height;
        }
        
        public function set height(value:int):void
        {
            _height = value;
        }
    }
}

 

工具转化类,ObjectUtils.as 类:

package com.vini123.utils
{
    import flash.net.registerClassAlias;
    import flash.utils.ByteArray;
    import flash.utils.describeType;
    import flash.utils.getDefinitionByName;
    import flash.utils.getQualifiedClassName;
    
    public class ObjectUtils
    {
        private static var _aliasList:Vector.<String> = new Vector.<String>();
        public function ObjectUtils()
        {
            
        }
        
        
        /**
         * 
         * @param source 源
         * @param deep  是否深复制
         * @return 
         * 
         */        
        public static function clone(source:* , deep:Boolean = true):*
        {
            if(!source)
            {
                return ;
            }
            
            if(deep)
            {
                var qualifiedClassName:String = getQualifiedClassName(source);
                if(_aliasList.indexOf(qualifiedClassName))
                {
                    var packageName:String = qualifiedClassName.replace("::",".");
                    //得到source的类的定义
                    var classType:Class = getDefinitionByName(qualifiedClassName) as Class;
                    //注册此别名和类
                    if(classType)
                    {
                        registerClassAlias(packageName , classType);
                        _aliasList.push(qualifiedClassName);
                    }
                    //注册内部的属性
                    registerVariables(source);
                    
                }
            }
            
            var byteArray:ByteArray = new ByteArray();
            byteArray.writeObject(source);
            byteArray.position = 0 ;
            
            trace(_aliasList);
            return byteArray.readObject();
        }
        
        
        /**
         * 
         * @param source
         * 注册某个类的公共属性(如果是复合类)所属的类的别名.
         * 
         */        
        private static function registerVariables(source:*):void
        {
            var xml:XML = describeType(source);
            var variable:XML;
            var variableType:String;
            var variablePackageName:String;
            var variableClassType:Class;
            
            var variableXml:XMLList;
            
            //判断source的类型,是对象或是Class
            if(source is Class)
            {
                variableXml = xml.factory.variable;  //获取类中的相关的属性
            }
            else
            {
                variableXml = xml.accessor;  //获取对象中相关的属性
            }
            
            for each(variable in variableXml)
            {
                variableType = variable.@type; //属性的类型,可能是Number,类等。
                
                if(variableType.indexOf("::")!=-1)
                {
                    //如果没有该类没有进行registerClassAlia
                    if(_aliasList.indexOf(variableType) == -1)
                    {
                        variablePackageName = variableType.replace("::","."); //得到类的别名
                        variableClassType = getDefinitionByName(variableType) as Class; //得到类名
                        if(variableClassType);
                        {
                            registerClassAlias(variablePackageName,variableClassType);
                            registerVariables(variableClassType);
                            _aliasList.push(variableType);
                        }
                    }
                }
            }
        }    
    }
}

 

运行后的结果:
trace的情况:
com.vini123.source::Roll,flash.geom::Point,com.vini123.source::Sky,flash.display::MovieClip
roll: 100 (x=100, y=100) 100 100
otherRoll: 200 (x=200, y=200) 200 200

第一行,是保留对象的类名。
第二行和第三行的结果,显示深复制的效果是有的。并且,在main中对Roll中的Point进行赋值时,深复制不到。其实,Sky类的hight,MovieClip的id同样不行。还冒明白。

最后的两个addChild.在舞台上,显示了两个圆,两个之间的x距离是80像素。证明显示对象的深复制是有效果的。因为该显示对象是在Roll中创建的。。。

到了现在,对象的深浅复制貌似意义不大。如果仅仅是复制的话。这些总结,只是个人的测试。欢迎朋友去完善和拓展吧。

不死心,为了进一步测试。这次用Flash cs6 创建一个影片剪辑,里边放了一张兔子的照片为背景。并有一个动态文本,infoTxt。将该影片剪辑连接到Skin类,Skin继承MovieClip

先创建一个Vector数组,初始化的时候,创建两个Skin,添加到显示列表,并填充到这个数组中。当点击舞台的时候,将这个数组中的Skin”深复制“到一个新的Vector中,释放旧的Skin,移出显示列表。2秒后,再将新数组中的Skin添加到显示列表。
(想法是美好的,当往新数组中深复制Skin的时候,Skin已经是undefined了。这个时候添加显然要报错。)
如是,证明,显示对象不能深复制。如果这样,和之前的结论不是互相矛盾么。

先看代码:

package com.vini123.view
{
    import flash.display.MovieClip;
    import flash.net.registerClassAlias;
    import flash.text.TextField;
    
    public class Skin extends MovieClip
    {
        public var infoTxt:TextField;
        
        public function Skin()
        {
            registerClassAlias("infoTxt",TextField);
        }
        
        public function set info(value:String):void
        {
            infoTxt.text = value;
        }
        
        public function Dispose():void
        {
            infoTxt.text = "";
            if(this.parent)
            {
                this.parent.removeChild(this);
            }
        }
    }
}

 

文档类:

package com.vini123
{
    import com.vini123.utils.ObjectUtils;
    import com.vini123.view.Skin;
    
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.events.MouseEvent;
    import flash.utils.setTimeout;
    
    [SWF(width = "1280" , height = "720" , frameRate="30")]
    public class Main extends Sprite
    {
        private var  _originalSkinList:Vector.<Skin> = new Vector.<Skin>();
        private var _newSkinList:Vector.<Skin> = new Vector.<Skin>();
        private var _hasClick:Boolean = false;
        private var _gap:int = 50;
        
        public function Main()
        {
            stage.align = StageAlign.TOP_LEFT;
            
            Init();
        }
        
        private function Init():void
        {
            for(var i:int = 0 ; i< 2 ; i++)
            {
                var skin:Skin = new Skin();
                skin.info = "这个是第" + (i + 1) + "只兔子!";
                addChild(skin);
                
                skin.x = (stage.stageWidth - skin.width *2 -_gap)/2 + i * (skin.width + 50);
                skin.y = stage.stageHeight * 0.5 - skin.height * 0.5 ;
                
                _originalSkinList.push(skin);
            }
            
            stage.addEventListener(MouseEvent.MOUSE_DOWN , mouseDownHandler);
        }
        
        private function mouseDownHandler(e:MouseEvent):void
        {
            if(!_hasClick)
            {
                _hasClick = true;
                for(var i:int =0 ; i< _originalSkinList.length ; i++)
                {
                    trace(ObjectUtils.clone(_originalSkinList[i]));
                    _newSkinList.push(ObjectUtils.clone(_originalSkinList[i]));
                }
                
                for(i = (_originalSkinList.length -1) ; i>= 0 ; i--)
                {
                    _originalSkinList[i].Dispose();
                    _originalSkinList.splice(i,1);
                }
                
                setTimeout( addAgain , 2000);
            }
        }
        
        private function addAgain():void
        {
            for(var i:int = 0 ; i< _newSkinList.length ; i++)
            {
                trace(_newSkinList[i]);
//                addChild(_newSkinList[i]);
//                _newSkinList[i].x = (stage.stageWidth - _newSkinList[i].width *2 -_gap)/2 + i * (_newSkinList[i].width + 50);
//                _newSkinList[i].y = stage.stageHeight * 0.5 - _newSkinList[i].height * 0.5 ;
            }
            
        }
    }
}