Как я могу скопировать коллекцию объектов переноса в actionscript?

#actionscript-3 #flex4

#actionscript-3 #flex4

Вопрос:

 public function create():ArrayCollection{

            var index:int = 0;
            var data:ArrayCollection = new ArrayCollection();
            var length:int = originalData.length;

            for(index; index < length; index  ){
                data.addItem(originalData[index]);
            } 

            return data;
        }
  
  • originalData — это исходное состояние моих данных из базы данных.
  • данные — это копия originalData, используемая для обработки в качестве поставщика для моего компонента списка.
  • Есть кнопка, которую я использую для вызова функции create() выше, это означало бы, что я хочу отменить все изменения в данных и вернуться ко всему, что у меня есть в originalData.

Но когда я отлаживаю свою функцию, originalData содержит все изменения, внесенные в данные.

Когда я использую

list.SelectedItem.thing = «новая строка»;

предполагается изменить data[index].thing, потому что data — это мой List.dataprovider. но это также изменяет originalData[index].thing, и эта коллекция не использовалась ни для чего, кроме как для создания собственной копии!

Я не знаю, почему это происходит. Я не знал, как сформулировать это поведение как запрос Google.

Пожалуйста, если вы не понимаете вопрос, прокомментируйте его, чтобы я мог попытаться сделать его более понятным. Это потребовало больше времени, чем стоит его функциональность.

Редактировать:

Я тоже пробовал это, но это не работает:

 public function create():ArrayCollection{

            var index:int = 0;
            var data:ArrayCollection = new ArrayCollection();
            var length:int = originalData.length;

            for(index; index < length; index  ){
// initializing a Item object.
                var dataItem:Item = new Item();
                dataItem = originalData[index] as Item;
                data.addItem(dataItem);
            } 

            return data;
        }
  

РЕДАКТИРОВАТЬ 2:

Основываясь на ваших ответах и некоторых исследованиях, я придумал эту универсальную функцию для копирования ArrayCollections, созданных из пользовательских объектов.

 public static function copy(objectClassName:String, objectClass:Class, arrayCollection:ArrayCollection):ArrayCollection{
            var index:int = 0;
            var length:int = arrayCollection.length;
            var copy:ArrayCollection = new ArrayCollection();

            for(index; index < length; index  ){
                registerClassAlias(objectClassName,objectClass);
                copy.addItemAt(ObjectUtil.copy(arrayCollection.getItemAt(index)) as objectClass,index);
            }
            return copy;
        }
  

Ответ №1:

Как говорит Том, это потому, что AS3 передается по ссылке. Если вы не хотите изменять исходные значения, вам следует, опять же, как говорит Том, создать их копии.

К счастью, в AS3 есть утилита для этого — ObjectUtils.copy. Попробуйте этот код вместо вашего оригинала:

 public function create():ArrayCollection{

            var index:int = 0;
            var data:ArrayCollection = new ArrayCollection();
            var length:int = originalData.length;

            for(index; index < length; index  ){
                data.addItem(mx.utils.ObjectUtil.copy(originalData[index]));
            } 

            return data;
        }
  

Обратите внимание, что copy() возвращает универсальный объект. Если вы хотите получить доступ к любому из его свойств типобезопасным способом, вам придется привести его к его типу.

Еще немного о передаче по ссылке. Допустим, у нас есть элементы a, b и c, плавающие в памяти. Вы помещаете их в массив (originalData). originalData теперь содержит ссылки на a, b и c. Затем вы создаете ArrayCollection и вставляете (снова) ссылки на a, b, c. Объекты a, b и c не являются тем, что хранится ни в массиве, ни в ArrayCollection. Итак, когда вы обновляете originalData[0], вы получаете ссылку на объект (a) и обновляете его.

Аналогично, когда вы обновляете ArrayCollection.getItemAt(0), вы получаете ту же ссылку и обновляете базовый объект, поэтому вы получаете поведение, которое получаете. Создание копии и вставка ее означает, что вы ссылаетесь на совершенно новый объект.

Комментарии:

1. При приведении вы ссылаетесь на это? ObjectUtil.copy(originalData[index]) как MyItem

2. Привет, Шон, не мог бы ты просмотреть мой код в последнем редактировании, в моем вопросе.

Ответ №2:

Я не привык к actionscript, но мне кажется, что вы помещаете ссылки на объекты из одного ArrayCollection в другой ArrayCollection. Поэтому, если вы измените эти объекты, это будет отражено в обоих ArrayCollections, поскольку они ссылаются на одни и те же объекты.

Чтобы избежать этого, вы должны сделать копии с исходных объектов, чтобы поместить их в новую ArrayCollection.

Комментарии:

1. Мне кажется, вы полностью поняли, что я имею в виду; очень приятно.

Ответ №3:

Чтобы создать глубокую копию массива и сохранить тип, используйте следующий метод:

 public static function clone(source:Object):* 
{ 
    var myBA:ByteArray = new ByteArray(); 
    myBA.writeObject(source); 
    myBA.position = 0; 

    return(myBA.readObject()); 
}
  

Это способ, предложенный Adobe.

Обновление: идея для функции копирования, безопасной для типов

 public static function copyTypeSafe( ac:ArrayCollection ):ArrayCollection
{
    var cloneAc:ArrayCollection = new ArrayCollection();

    if( ac.length ==  0 ) {
        return cloneAc;
    }

    var className:String = getQualifiedClassName( ac.getItemAt(0) );
    registerClassAlias( className, (getDefinitionByName( className ) as Class ) );

    for each (var obj:Object in ac) 
    {
        cloneAc.addItem( ObjectUtil.copy( obj ) );
    }

    return cloneAc;

}
  

Комментарии:

1. Да, я использовал это, но это сохраняет только тип arraycollection, элементы, содержащиеся в нем, преобразуются в типы объектов, которые мне бесполезны.

2. Ах, да, вы правы… затем вы должны использовать метод копирования, как предлагает Шон. Я отредактировал свой ответ и добавил идею сделать тип функции копирования безопасным.

Ответ №4:

Вам нужно выполнить вызов registerClassAlias для каждого из классов внутри вашей коллекции, затем просто используйте функцию clone с ByteArray, предложенную выше, и она будет работать нормально. Ключ в том, чтобы выполнить вызов registerClassAlias для каждого типа внутри ArrayCollection, который вы хотите поддерживать. В моем случае:

 var productGroupClassName:String = getQualifiedClassName(ProductGroup);
                registerClassAlias( productGroupClassName, ProductGroup );
                var productClassName:String = getQualifiedClassName(Product);
                registerClassAlias( productClassName, Product );
                //Need to create a copy so the original values will not be altered
                dataProvider = copyTypeSafe(EnalityData.productsInfo);