Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Блоги Правила Справка Пользователи Календарь Сообщения за день
 

Вернуться   Форум Flasher.ru > Flash > ActionScript 3.0

Версия для печати  Отправить по электронной почте    « Предыдущая тема | Следующая тема »  
Опции темы Опции просмотра
 
Создать новую тему Ответ
Старый 13.11.2013, 14:44
a7s1h1 вне форума Посмотреть профиль Отправить личное сообщение для a7s1h1 Найти все сообщения от a7s1h1
  № 1  
Ответить с цитированием
a7s1h1

Регистрация: Oct 2013
Сообщений: 126
По умолчанию Система удаления ненужных объектов и слушателей

Прошу помочь советом.
Дело в том, что у меня, наверное, обоснованное, но всё же параноидальное стремление удалять объекты и слушатели, которые больше не нужны.

Архитекрута моего проекта такова:
Main хранит "уровни" и контролирует переход между ними.
Уровни - это объекты Sprite с соответствующими детьми (надписями, кнопками, объектами и т.д.).
Переход из уровня 1 в уровень 2 представляет собой удаление со сцены уровня 1 и помещение туда уровня 2.
При этом необходимо удалить не только сам уровень 1 со всеми его слушателями, но и всех его детей и внуков с их слушателями.
К сожалению, функции "удалить всю семью со слушателями на всех уровнях ниже вызываемого объекта", откликающуюся на removed_from_stage, я не нашёл (подозреваю, что такой и нет), поэтому делаю так:
При создании любого объекта, которому предстоит иметь детей, я ставлю проверку события removed_from_stage, и в cleanup() удаляю всех его слушателей при помощи removeEventListener, а также всех детей при помощи
Код AS3:
while (this.numChildren > 0) {this.removeChildAt(0) };
.
Соответственно, при удалении уровня 1 удаляются его дети, которые при своём удалении удаляют своих детей и т.д. И все удаляют своих слушателей.
Но при этом получается, что такую "чистилку" приходится приписывать каждому объекту, ведь даже при использовании
Код AS3:
while (this.numChildren > 0) {this.removeChildAt(0) };
удаляются только дети, а "внуки" либо остаются, либо от потери родителя начинают выдавать ошибки.

Прошу прощения за корявое объяснение, но по-другому не смог(
В книгах написано, что ненужные слушатели и объекты надо удалять.
Но неужели для этого надо каждому объекту добавлять слушателя removed_from_stage, чтобы он "почистился" сам и заставил "почиститься" своих детей?

По большому счёту вопрос заключается в том, как это делать правильно, т.е. "как лучше чистить детей и слушателей"?

Старый 13.11.2013, 14:53
КорДум вне форума Посмотреть профиль Отправить личное сообщение для КорДум Найти все сообщения от КорДум
  № 2  
Ответить с цитированием
КорДум
 
Аватар для КорДум

блогер
Регистрация: Jan 2008
Адрес: syktyvkar
Сообщений: 3,803
Записей в блоге: 10
Если удалить ссылку на "корневой" объект, содержащий в себе ссылки на другие объекты (и никто из-вне на них ссылки не имеет), то GC заберет все это скопом без лишних слов вне зависимости, какая там иерархия ссылочной вложенности. От событий надо отписываться в таком случае только у таймеров и enterFrame, чтобы зря не отрабатывали, пока GC сподобится прийти.
__________________
тут я

Старый 13.11.2013, 15:03
Tails вне форума Посмотреть профиль Отправить личное сообщение для Tails Найти все сообщения от Tails
  № 3  
Ответить с цитированием
Tails
 
Аватар для Tails

блогер
Регистрация: Dec 2008
Адрес: г. Чебоксары
Сообщений: 2,259
Записей в блоге: 6
КорДум,
Таймер и дисплей объекты являются наследниками EventDispatcher. Соответственно, ссылки подписчиков они хранят сами в себе.

Дисплей объект, находящийся на сцене, перед отрисовкой получает событие enterFrame. Это происходит, когда внешний код проверяет, есть ли у него подписки и высылает событие. В случае удаления объекта со сцены, про его подписчиков никто не знает, кроме самого объекта, а значит, удалять его подписчиков не обязательно.

С таймером похожая ситуация, удалять подписчиков не обязательно. Важно - останавливать таймер для удаления.
__________________
Дети не должны знать о своих родителях

Старый 13.11.2013, 15:07
КорДум вне форума Посмотреть профиль Отправить личное сообщение для КорДум Найти все сообщения от КорДум
  № 4  
Ответить с цитированием
КорДум
 
Аватар для КорДум

блогер
Регистрация: Jan 2008
Адрес: syktyvkar
Сообщений: 3,803
Записей в блоге: 10
Tails,
Не понял. Подпишите объект на enterFrame и удалите ссылку на него. Его хэндлер будет срабатывать так же каждый кадр. Вызовите GC и посмотрите, что хэндлер больше не срабатывает. То же самое с событием тика таймера.
__________________
тут я

Старый 13.11.2013, 15:11
a7s1h1 вне форума Посмотреть профиль Отправить личное сообщение для a7s1h1 Найти все сообщения от a7s1h1
  № 5  
Ответить с цитированием
a7s1h1

Регистрация: Oct 2013
Сообщений: 126
правильно ли я понимаю, что если при удалении "главного родителя" удалить всех его детей, и следующей же строкой запустить
Код AS3:
System.gc()
, то все "потомки" этого "главного родителя" вместе со слушателями будут уничтожены?

Старый 13.11.2013, 15:16
Tails вне форума Посмотреть профиль Отправить личное сообщение для Tails Найти все сообщения от Tails
  № 6  
Ответить с цитированием
Tails
 
Аватар для Tails

блогер
Регистрация: Dec 2008
Адрес: г. Чебоксары
Сообщений: 2,259
Записей в блоге: 6
Цитата:
Сообщение от КорДум Посмотреть сообщение
Tails,
Не понял. Подпишите объект на enterFrame и удалите ссылку на него. Его хэндлер будет срабатывать так же каждый кадр. Вызовите GC и посмотрите, что хэндлер больше не срабатывает. То же самое с событием тика таймера.
Да, всё верно. Потому-что дисплей объект находится на сцене, или в потомке который лежит на сцене. Ссылка на него есть, он не удалится а entarFrame будет вызываться. Я имею ввиду, что если этот объект подписал сам себя на enterFrame, но его удалили со сцены или потомка который на сцене (stage == null) - в этом случае объект удалится, даже не смотря на то, что он сам себя подписал на enterFrame.

С таймером попроще, он не дисплей объект и не может находиться в неком нативном списке.
Пока таймер запущен и тикает, флеш плеер имеет на него собственную внутреннюю ссылку или что-то вроде того. В запущенном состояний, такой таймер не удалится никогда. Что-бы удалить, его надо обязательно остановить. Затем, как обычно обнулить ссылки, ссылающиеся на него. Однако, не обязательно отписывать подписчиков на этот таймер, так как всю информацию о своих подписчиках таймер хранит только в себе. (EventDispatcher)
__________________
Дети не должны знать о своих родителях

Старый 13.11.2013, 15:18
КорДум вне форума Посмотреть профиль Отправить личное сообщение для КорДум Найти все сообщения от КорДум
  № 7  
Ответить с цитированием
КорДум
 
Аватар для КорДум

блогер
Регистрация: Jan 2008
Адрес: syktyvkar
Сообщений: 3,803
Записей в блоге: 10
Tails, ок, я думал, что чего-то не понимаю. Я говорил про объект, который подписан на событие таймера, не про сам таймер. На самом деле мы недопоняли друг друга =)

Добавлено через 8 минут
a7s1h1,
Цитата:
правильно ли я понимаю, что если при удалении "главного родителя" удалить всех его детей...
да, только удалять детей не обязательно. Если на них ссылок из других мест, то они удалятся сами автоматически.
__________________
тут я

Старый 13.11.2013, 15:31
Tails вне форума Посмотреть профиль Отправить личное сообщение для Tails Найти все сообщения от Tails
  № 8  
Ответить с цитированием
Tails
 
Аватар для Tails

блогер
Регистрация: Dec 2008
Адрес: г. Чебоксары
Сообщений: 2,259
Записей в блоге: 6
Главное, что мы поняли друг-друга

a7s1h1,
Удалять внуков не обязательно, если вы удаляете их родителя, в котором они лежат. Главное, что-бы на этих внуков ещё кто-то не ссылался, кроме их родителя. КорДум вам уже это посоветовал.

Удалять подписчиков можно и нужно, особенно если вы не на 100% понимаете весь замут с этими диспетчерами. Вы так-же можете использовать при подписке - "слабые ссылки", которые не препятствуют удалению объекта, если на него больше никто другой не ссылается.

System.gc()
Работает только в дебаговом режиме, (нужно для отладки). В релизной версий, вы никак не можете самостоятельно вызвать или повлиять на gc.

Ваша главная задача для удаления - не оставлять ссылок, исключением могут быть только "слабые ссылки".
__________________
Дети не должны знать о своих родителях

Старый 13.11.2013, 15:51
a7s1h1 вне форума Посмотреть профиль Отправить личное сообщение для a7s1h1 Найти все сообщения от a7s1h1
  № 9  
Ответить с цитированием
a7s1h1

Регистрация: Oct 2013
Сообщений: 126
я, возможно, не так понял, но у меня при удалении "главным родителем" всех своих детей "внуки" никуда не пропадают, толькое если их не уничтожит сам родитель. Другими словами,
Объект 1 - родитель для объекта 2
Объект 2 - родитель для объекта 3
При удалении объектом 1 всех своих детей объект 3 по-прежнему остаётся. А при повторном создании объекта 2 у него вместо одного ребёнка становится уже 2 (проверял через trace(numChildren))

Причём, я проверил, на некоторые их неудалённых детей больше никто не ссылался.

Слабые ссылки я ещё не пробовал, но теперь это уже не главная проблема.
Если я не смогу вызывать System.gc() в релизе, значит на него вообще не имеет смысла расчитывать в плане чистки в нужные мне моменты?

Я совсем запутался. Поможет ли для чистки такой подход:
В каждом классе, подлежащем помещению на сцену, писать:

Код AS3:
package {
	import flash.display.Sprite;
	import flash.events.Event;
 
	public class ClassName extends Sprite {
 
		// свойства
		child:Object; // какой-то объект-ребёнок
 
		// Контсруктор
		public function ClassName() {
			addEventListener(Event.ADDED_TO_STAGE, init);
		}
 
		private function init(e:Event):void {
			removeEventListener(Event.ADDED_TO_STAGE, init);
			addEventListener(Event.REMOVED_TO_STAGE, cleanup);
			// добавляем детей
			child = new Child();
			addChild(child);
			// добавляем слушателей детям (при необходимости)
			child.addEventListener(Event.ENTER_FRAME,childupdate)
			// добавляем слушателей себе
			addEventListener(Event.ENTER_FRAME,update)
		}
 
		private function cleanup(e:Event):void {
			// удаляем слушателей детей
			child.removeEventListener(Event.ENTER_FRAME,update)
			// удаляем детей
			while (numChildren > 0) { removeChildAt(0) };
			// удаляем своих слушателей
			removeEventListener(Event.ENTER_FRAME,update)
			removeEventListener(Event.REMOVED_TO_STAGE, cleanup);
		}
 
		private function update():void {
			//
		};
 
		private function childupdate():void {
			//
		};
	}
}

Старый 13.11.2013, 16:22
Tails вне форума Посмотреть профиль Отправить личное сообщение для Tails Найти все сообщения от Tails
  № 10  
Ответить с цитированием
Tails
 
Аватар для Tails

блогер
Регистрация: Dec 2008
Адрес: г. Чебоксары
Сообщений: 2,259
Записей в блоге: 6
Создайте в родительском конструкторе столько детей, сколько вам нужно.
Добавьте их в родителя:
Код AS3:
addChild(child);
Подпишитесь в конструкторе на обновление, если вам необходимо:
Код AS3:
addEventListener(Event.ENTER_FRAME,update)
Тут переудалять детей или переотписываться от события нет необходимости, так-как все ссылки содержит родительский класс ClassName.

Если кто-то создать ClassName и добавит его на сцену, он создаст своих детей и будет обновляться. Если ClassName кто-то удалит, GC автоматически заберёт его и всё его содержимое, так-как кроме ClassName, о нём больше никто и ничего не знает.
__________________
Дети не должны знать о своих родителях

Создать новую тему Ответ Часовой пояс GMT +4, время: 23:52.
Быстрый переход
  « Предыдущая тема | Следующая тема »  

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


 


Часовой пояс GMT +4, время: 23:52.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.