#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);