如何在ActionScript中创建对象的未引用副本

时间:2014-01-06 16:07:20

标签: flex object actionscript reference

Flex和ActionScript的新功能对我来说很光鲜。

我有一个充满自定义对象的ArrayCollection。我需要能够创建此Array的副本,执行一些函数以及对Array和对象的修改。然后我需要在开始之前将其重新恢复为原始存储的副本。

问题(以及我发现并尝试修复的错误)是我似乎无法创建不直接引用原始数据的此数组的副本。即:对副本的修改也会修改原件。

private var original:ArrayCollection = new ArrayCollection();
...

private function doStuff()
{
    var modified:ArrayCollection = original;
    for each (var myObj:CustomObject in modified)
        ...
}

我最接近的是使用ObjectUtil.clone ...

private var original:ArrayCollection = new ArrayCollection();
...

private function doStuff()
{
    var modified:ArrayCollection = ObjectUtil.clone(original);
    for each (var myObj:CustomObject in modified)
    {
        //Error here as the clone worked, however the objects in the array reverted to the base Object Class and couldn't be cast back to their actual CustomObject type
    }
}

这是一个有效的例子:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
               xmlns:s="library://ns.adobe.com/flex/spark" 
               xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"
               creationComplete="application1_creationCompleteHandler(event)">
    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            import mx.events.FlexEvent;

            private var originals:ArrayCollection;
            protected function application1_creationCompleteHandler(event:FlexEvent):void
            {
                originals = new ArrayCollection();
                for (var i:int = 0; i <= 5; i++)
                {
                    var myObj:CustomObject = new CustomObject();
                    originals.addItem(myObj);
                }
                doStuff();
            }

            private function doStuff():void
            {
                var modified:ArrayCollection = clone(originals);
                for (var i:int = 0; i < modified.length; i++)
                {
                    var myDupObj:CustomObject = modified[i] as CustomObject;
                    //do stuff
                    trace(myDupObj);
                }
            }

            private function clone(source:Object):*
            {
                var myBA:ByteArray = new ByteArray();
                myBA.writeObject(source);
                myBA.position = 0;
                return(myBA.readObject());
            }

        ]]>
    </fx:Script>
    <fx:Declarations>
        <!-- Place non-visual elements (e.g., services, value objects) here -->
    </fx:Declarations>
</s:Application>

和CustomObject.as

package
{
    public class CustomObject
    {
        public var a:String;
        public var b:String;
        public var c:String;

        public function CustomObject()
        {
            a = "Hello";
            b = "World";
            c = "Good-Bye";
        }
    }
}

4 个答案:

答案 0 :(得分:0)

对象的变量,基本上是指向该对象的指针。所以,当你这样做时:

var modified:ArrayCollection = original;

Original是一个指向ArrayCollection的指针,该指针现在也存储在修改后的变量中。但是,他们仍然指向相同的ArrayCollection。

你说你试过克隆,但提到它不起作用的事实 - 你没有详细说明它为什么不起作用。

要进行复制,您可以在ObjectUtil中使用clonecopy方法。我认为克隆执行了深层复制,这意味着所有引用的对象也被复制,但复制没有复制引用的对象,因此它是一个“浅”副本。我可能会改变它。

我使用此方法在一个项目中复制ArrayCollection;我相信它是ObjectUtil.clone的修改版本。

// clone method in ObjectUtils needs a UID; this one doesn't
public static function clone(source:Object):*
{
    var myBA:ByteArray = new ByteArray();
    myBA.writeObject(source);
    myBA.position = 0;
    return(myBA.readObject());
}

答案 1 :(得分:0)

更改doStuff()函数,如下所示: -

private function doStuff():void
        {
            var modified:ArrayCollection = new ArrayCollection()
                modified.addAll(ObjectUtil.copy(originals.list) as IList);

            //following code only for testing 
            for (var i:int = 0; i < modified.length; i++)
            {
                modified[i].a = "Bye";
                trace(modified[i].a);
                trace(originals[i].a);
            }
        }

答案 2 :(得分:0)

如果将[RemoteClass]元数据添加到CustomObject类,ObjectUtil.clone(original)方法将起作用。

package
{
    [RemoteClass]
    public class CustomObject
    {
        public var a:String;
        public var b:String;
        public var c:String;
    }
}

这会阻止您在迭代克隆的集合时遇到强制转换错误。请记住,如果您的CustomObject具有其他“自定义”类型的任何属性,那么这些类也需要[RemoteClass]。

答案 3 :(得分:0)

经过一些研究后,我得出结论,这里使用的各种自定义类可能太复杂,无法使用常规实用程序完全复制。它们还用于与我正在尝试修复的特定事物无关的应用程序的各个其他方面,因此我无法真正改变它们以使它们更容易工作。

我最终循环遍历原始arraycollection,使用原始属性创建新对象... ie:

        var modified:ArrayCollection = new ArrayCollection();
        for each (var myObject:CustomObject in original)
        {
            var newObject:CustomObject= new CustomObject();
                                    //... setup properties
            modified.addItem(newLayer);
        }