В AS3 удаление дочернего элемента со стадии удаляет все ссылки на него, чтобы он мог быть очищен сборщиком мусора? - PullRequest
0 голосов
/ 14 марта 2020

Я создаю приложение AIR, которое имеет основной класс, который создает множество экземпляров мувиклипа и добавляет их в контейнер. Во время использования приложения эти клипы часто уничтожаются и создаются новые.

Когда я создаю эти мувиклипы, мой основной класс добавляет к ним прослушиватели событий. У мувиклипов также есть слушатели событий.

Я использую следующую функцию, чтобы удалять все эти мувиклипы из их контейнера всякий раз, когда я обновляю дисплей:

        for (var i = 0; i < this.mainContainer.numChildren; i++) 
        {
            mainContainer.removeChild(mainContainer.getChildAt(i));
            //mainContainer.getChildAt(i)=null;
        }

Мне интересно если этого достаточно для подготовки этих экземпляров к сборке мусора ie убивает ли это прослушиватели событий, добавленные моим основным классом? Или мне нужно go пройти и удалить прослушиватели событий перед удалением каждого дочернего элемента?

Кроме того, где обнуление каждого экземпляра вписывается в это? Выше закомментированная строка выдает ошибку:

1105: Target of assignment must be a reference value.

Спасибо

Ответы [ 3 ]

2 голосов
/ 14 марта 2020

Удалить ВСЕ дочерние элементы

Ваш скрипт не удалит все дочерние элементы mainContainer , а только половину. Почему? Поскольку каждый раз, когда вы удаляете ребенка, остальные закрываются, чтобы съесть освобожденный индекс, поэтому ваш сценарий удаляет их следующим образом:

Initial picture  :  0 1 2 3 4 5 6 7 8 9
Remove child at 0:  1 2 3 4 5 6 7 8 9
Remove child at 1:  1 3 4 5 6 7 8 9
Remove child at 2:  1 3 5 6 7 8 9
Remove child at 3:  1 3 5 7 8 9

Правильный способ удаления ALL дочерних элементов из данный контейнер является либо назад l oop, который удаляет в данный момент последнего потомка:

for (var i = mainContainer.numChildren - 1; i >= 0; i--) 
{
    mainContainer.removeChildAt(i);
}

, либо , тогда как l oop, который удаляет дочерние элементы на глубине 0, пока они есть:

while (mainContainer.numChildren > 0)
{
    mainContainer.removeChildAt(0);
}

Однако есть гораздо более простой способ опустошить контейнер (доступно из Fla sh Player 11 и далее):

mainContainer.removeChildren();

Сборщик мусора

Что касается G C, общая идея состоит в том, что нет действительных ссылок из области приложения (вещи, прикрепленные к stage и stati c членов класса) к этим объектам.

Если вы уверены, что ничто в области действия не относится к ним или не подписано на них, то G C выполнит свою работу правильно.

Лично я всегда сочиняю метод с именем destroy (...) , который демонтирует все в данном объекте: отменяет подписку на все прослушиватели событий, обрабатывает Array s длиной 0, присваивает null каждому и каждому типу переменной Object , удаляет детей и т. д. c.

Я также согласен с Jyreel , полагаться на отображение контейнеров для хранения вещей для вас - это не способ программиста, а использование этого способа, или для разработки более сложных структур данных, это решение зависит от вас и вашего понимания.

0 голосов
/ 14 марта 2020

На самом деле ответ зависит от типа слушателя. Существует два «сильных» и «слабых» слушателя, первый из которых должен быть явно удален, если только он не прослушивает один и тот же объект, а второй - нет. Они отличаются установкой параметра useWeakReference при вызове addEventListener() в значение true для слабого и false (по умолчанию) для сильного задания.

Пример: если ваш класс M C имеет это в коде:

public function Example1() {
    ....
    if (stage) init(); else addEventListener(Event.ADDED_TO_STAGE,init);
}
private function init(e:Event=null) {
    removeEventListener(Event.ADDED_TO_STAGE,init);
}

, этот слушатель уже обработан кодом, но вы должны сказать stage.addEventListener(...) в init() , они должны быть удалены явно, прежде чем экземпляр этого класса может быть собран сборщиком мусора, при условии, что слушатель не объявлен как «слабый». Однако, если вы скажете добавить прослушиватель следующим образом:

addEventListener(Event.ENTER_FRAME,someFunction);

, эти прослушиватели не нужно явно удалять для сбора мусора экземпляра, даже если он «сильный», потому что они представляют только внутренние ссылки , которые становятся недействительными рядом с объектом, на который они ссылаются.

0 голосов
/ 14 марта 2020

Вот что я нашел в Google: «Если удаленный объект не содержит ссылок (ссылки на него отсутствуют), то да - сам элемент выбирается сборщиком мусора, а также обработчиками / слушателями событий связанный с ним "

Лично я считаю создание спрайта с именем" gameObjects "и затем addchild (gameObjects), а затем создание массива и затем выполнение arrayName.pu sh (объект) намного проще, чем создание контейнер, но я никогда не работал с контейнерами.

Если вам нужен код для удаления прослушивателей событий, это почти то же самое, что и добавление их, просто переключите add с remove.

Здесь Это грубое представление о коде, который вам понадобится для использования массивов и спрайтов, чтобы делать то же самое, что вы пытаетесь сделать, но если вам легче найти контейнеры, просто игнорируйте эту часть:

private var gameObjectsArray:Array;
private var gameObjects:Sprite;
public function Start(){
            gameObjects = new Sprite();
            addChild(gameObjects);
            gameObjectsArray = new Array();
            var myObject:object = new object();
            gameObjects.addChild(object);
            gameObjectsArray.push(object);
}

, если это не так затем в игре просто замените «gameObjects» на любое имя и замените «объект» экземпляром, который вы создаете, изменяете и добавляете в массив.

TL: DR - Вам не нужно отдельно удалять прослушиватели событий, если вы удаляете объекты, с которыми они связаны. Я не совсем уверен, но я думаю, что закомментированная строка не нужна, но я не знаю много о контейнерах. Попробуйте кучу разных вещей, и вы найдете ответ. Иногда использование трассировки («1») с заменой 1 на любую строку или переменную без кавычек очень помогает.

...