Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Отписывание от событий (http://www.flasher.ru/forum/showthread.php?t=174650)

s3dworld 30.01.2012 13:35

Отписывание от событий
 
Всем доброго дня!

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

Код AS3:

package 
{
        import flash.display.MovieClip;
        import flash.events.Event;
 
        public class main extends MovieClip
        {
                public function main()
                {
                        if(stage)
                                Start();
                        else
                                addEventListener(Event.ADDED_TO_STAGE,OnAddedToStage);
                }
 
                private function OnAddedToStage(_event:Event):void
                {
                        removeEventListener(Event.ADDED_TO_STAGE,OnAddedToStage);
                        Start();
                }
 
                private function Start():void
                {
 
                }
 
        }
 
}

Вроде всё понятно. Такой пример я видел много раз. В некоторых же примерах встречал вот так:

Код AS3:

package 
{
        import flash.display.MovieClip;
        import flash.events.Event;
 
        public class main extends MovieClip
        {
                public function main()
                {
                        if(stage)
                                Start();
                        else
                                addEventListener(Event.ADDED_TO_STAGE,OnAddedToStage);
                }
 
                private function OnAddedToStage(_event:Event):void
                {
                        Start();
                }
 
                private function Start():void
                {
 
                }
 
        }
 
}

То есть особо не уделяется внимания освобождению прослушки. Я же пишу вот так:

Код AS3:

package 
{
        import flash.display.MovieClip;
        import flash.events.Event;
 
        public class main extends MovieClip
        {
                private var isAddedToStageListener:Boolean=false;
 
                public function main()
                {
                        if(stage)
                        {
                                Start();
                        }
                        else
                        {
                                isAddedToStageListener=true;
                                addEventListener(Event.ADDED_TO_STAGE,OnAddedToStage);
                        }
                }
 
                private function OnAddedToStage(_event:Event):void
                {
                        if(isAddedToStageListener) removeEventListener(Event.ADDED_TO_STAGE,OnAddedToStage);
 
                        Start();
                }
 
                private function Start():void
                {
 
                }
 
        }
 
}

Для меня конечно мой вариант правильный, так как он сам подписывает и сам отписывает (но выглядит не очень красиво). Как вообще стоит писать? Просто будет ли Flash сам отписывать события или же многие спустя рукава на всё это смотрят?

TanaTiX 30.01.2012 13:41

Используйте мягкие ссылки, названия методов - с маленькой буквы.
Какая необходимость в использовании метода Start?

s3dworld 30.01.2012 13:45

TanaTiX
Цитата:

Используйте мягкие ссылки
Что за мягкие ссылки? Впервые слышу.

Цитата:

названия методов - с маленькой буквы
Ну это на самом деле дело стиля. Я уже выработал свой стиль работая на C++, так что я уже привык.

Цитата:

Какая необходимость в использовании метода Start?
Так ведь не всегда вызовется функция OnAddedToStage(), то есть stage может быть уже получен (точнее клип в него добавлен). Следовательно какой смысл дублировать код в OnAddedToStage() и до него, если можно всё в одну функцию вынести?

Stitch512 30.01.2012 13:49

А в чем смысл флажка isAddedToStageListener? Отписываемся если он true, но если false то по коду OnAddedToStage и не придет...

s3dworld 30.01.2012 13:54

Stitch512
Согласен! Упустил из виду. Тут значит проблем нет. Раз вызвалась, значит подписывались и всегда можно отписывать. Косяк мой.

Тогда у меня 3 вопроса:

1. Что за мягкие ссылки?
2. Можно ли отписывать событие, если оно не было подписано (что вообще будет?)
3. delete используется для удаления полей в динамическом классе, а можно ли как-то удалить сам динамический класс из памяти (я конечно понимаю что он сам удалится со временем если на него нет ссылок, но а самом можно?)?

in4core 30.01.2012 14:22

Цитата:

2. Можно ли отписывать событие, если оно не было подписано (что вообще будет?)
Ничего не будет, ни кому не помешает :) тоесть проверки делать не надо в вашем случае
Цитата:

3. delete используется для удаления полей в динамическом классе, а можно ли как-то удалить сам динамический класс из памяти (я конечно понимаю что он сам удалится со временем если на него нет ссылок, но а самом можно?)?
Только GC может его снести , когда придет время, если ссылки убиты, в дебаге же можно запускать ГЦ вручную вроде, но зачем ?:)

ProxyGreen 30.01.2012 14:25

Под мягкими ссылками видимо имеется ввиду параметр "useWeakReference" в методе:
addEventListener(Event.ADDED, listener, false, 0, true);
GC вроде как не учитывает слабые ссылки и по своему усмотрению может удалить завалявшийся слушатель. Но здесь не подходящий случай имхо.

Dukobpa3 30.01.2012 14:32

>> 1. Что за мягкие ссылки?
Код AS3:

addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, <b>useWeakReference:Boolean = trueb>):void

>> 2. Можно ли отписывать событие, если оно не было подписано (что вообще будет?)
Код AS3:

hasEventListener(type:String):Boolean
// Проверяет, имеет ли объект EventDispatcher прослушиватели, зарегистрированные для определенного типа события.

>> 3. delete используется для удаления полей в динамическом классе, а можно ли как-то удалить сам динамический класс из памяти (я конечно понимаю что он сам удалится со временем если на него нет ссылок, но а самом можно?)?
Ну это не плюсы, тут виртуальная машина всё решает. Всё что мы можем сделать это занулить все ссылки на объект дабы повысить вероятность очистки. Вручную сборщик мусора запускать не рекомендуется.

справка

TanaTiX 30.01.2012 14:33

Цитата:

Ну это на самом деле дело стиля. Я уже выработал свой стиль работая на C++, так что я уже привык.
В действительности есть некие соглашения, принятые во флеш-сообществе. К тому же так рекомендует адоб. Писал бы я на С++, старался бы писать с большой, но это флеш. Программа от этого иначе работать не будет, а вот коллеги не поймут, будут лишние вопросы и пр.
Цитата:

Так ведь не всегда вызовется функция OnAddedToStage(), то есть stage может быть уже получен (точнее клип в него добавлен). Следовательно какой смысл дублировать код в OnAddedToStage() и до него, если можно всё в одну функцию вынести?
По указанному коду функция всегда вызывается вначале работы экземпляра класса, т.е. по сути при добавлении на сцену. Почему тогда все ее содержимое не поместить в onAddedToStage? Хотя соглашусь, что бывают ситуации, когда нужно разделять.
На остальное вроде ответили.

Добавлено через 1 минуту
Dukobpa3, по 2-му пункту согласен с in4core

expl 30.01.2012 14:41

Люди, откуда такая мантра: "не отписался от события - утекла память".
Подписка подразумевает, что мы создаем ссылку на слушатель внутри dispatcher-a. Если dispatcher и владелец слушателя - одно и то же лицо - память никуда не потечёт.

Самый простой эксперимент - создаем класс-наследник Sprite, внутри вешаем trace на ENTER_FRAME в конструкторе. Создаем этот класс и удаляем на него ссылки. Наблюдаем некоторое время приход трейсов. Запускаем GC - трейсы пропали.
В принципе, можно даже просто подписаться на спрайт и не создавать на него ссылок нигде - то же самое будет (он на нас ссылается, а мы на него - нет).

Но от ENTER_FRAME как раз надо отписываться - ибо нефиг процессор грузить пока до тебя GC добирается.

А вешаться на события на мягких ссылках не стоит по одной причине:
- все время, пока GС будет добираться до объекта - объект будет исправно обрабатывать события - грузить проц тобишь.

TanaTiX 30.01.2012 14:47

Цитата:

А вешаться на события на мягких ссылках не стоит по одной причине:
- все время, пока GС будет добираться до объекта - объект будет исправно обрабатывать события - грузить проц тобишь.
Откуда такая информация? Мягкие ссылки - одна из рекомендаций адоба.

s3dworld 30.01.2012 14:48

Ребят, всем спасибо за ответы. У меня вопрос по стилю ведения проекта (чтобы новой темы не создавать). Я как-то от C++ приучился. Вот главным классом у меня всегда является main.as, он не лежит ни в каком пространстве имён. Далее я решил создать пакет Game и в него впихнуть класс Game. Получилось вот так:

Код:

Game/Game.as
main.as

Но при создании объекта Game в классе main приходится писать так:

Код AS3:

var game:Game=new Game.Game();

Работаю в FlashDevelop и тут каждая папка как пакет получается. Может стоит писать так:

Код:

Game/...
Game.as
main.as

Или это тоже какие-то подводные камни несёт? А то у меня сложилось такое впечатление, что лучше не называть пакеты такими же названиями как имена классов. Так ли это?

TanaTiX 30.01.2012 14:50

s3dworld
Цитата:

чтобы новой темы не создавать
На форуме правило - один вопрос, одна тема.

s3dworld 30.01.2012 14:52

Извиняюсь, создаю новую тему...

HardCoder 30.01.2012 14:59

Цитата:

Сообщение от TanaTiX (Сообщение 1059997)
Откуда такая информация? Мягкие ссылки - одна из рекомендаций адоба.

Думаю, имеется в виду что GC не сразу удалит слушатель в виду соображений что памяти достаточно. Вот слушатель и будет сидеть в памяти, не влияя на нее. А вот на проц будет грузить, потому что слушатель будет все время выполняться, пока GC не увидит что памяти мало и не удалит его.

TanaTiX 30.01.2012 15:00

Мягкие ссылки не отменяют отписывание от событий.

HardCoder 30.01.2012 15:05

Согласен. Лично я не всегда доверяю мягким ссылкам и отписываюсь от событий в явном виде. А что - перестраховаться не помешает. Это вырабатывает привычку, чтобы потом не искать утечки.

expl 30.01.2012 15:38

Цитата:

Цитата:
А вешаться на события на мягких ссылках не стоит по одной причине:
- все время, пока GС будет добираться до объекта - объект будет исправно обрабатывать события - грузить проц тобишь.

Откуда такая информация? Мягкие ссылки - одна из рекомендаций адоба.
Это не информация - это чистая логика: "Отписываться лучше, чем не отписываться с мягкими ссылками".

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

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

А слушать или не слушать Adobe - это зависит от Вашего подхода к управлению памятью в приложении в целом.

crazyone 30.01.2012 15:49

Цитата:

Код AS3:

public function main()
                {
                        if(stage)
                        {
                                Start();
                        }
                        else
                        {
                                isAddedToStageListener=true;
                                addEventListener(Event.ADDED_TO_STAGE,OnAddedToStage);
                        }
                }


Неизвестно, откуда это пошло, но это условие абсолютно лишнее.
Да, в конструкторе класса приложения переменная stage доступна, но ADDED_TO_STAGE сработает в любом случае после конструктора, поэтому достаточно написать так:

Код AS3:

package 
{
        import flash.display.MovieClip;
        import flash.events.Event;
 
        public class main extends MovieClip
        {
                public function main()
                {
                        addEventListener(Event.ADDED_TO_STAGE,OnAddedToStage);
                }
 
                private function OnAddedToStage(_event:Event):void
                {
                        removeEventListener(Event.ADDED_TO_STAGE,OnAddedToStage);
                        Start();
                }
 
                private function Start():void
                {
 
                }
        }
 }


TanaTiX 30.01.2012 15:52

Цитата:

Отписываться лучше, чем не отписываться с мягкими ссылками
Повторюсь
Цитата:

Мягкие ссылки не отменяют отписывание от событий.
Я всегда (где это возможно) использую мягкие ссылки И отписываюсь от событий.
Цитата:

А слушать или не слушать Adobe - это зависит от Вашего подхода к управлению памятью в приложении в целом.
Да, к рекомендациям адоба можно (а порой и нужно) относиться критично, но ИМХО не в данном случае.
Цитата:

Ведь если вы забыли отписаться и ссылка была _не_ мягкой - это обнаружить будет проще, чем если бы ссылка была мягкой.
А если не отписался и ссылка не мягкая когда и на каком этапе обнаружишь ошибку?

expl 30.01.2012 17:00

2TanaTiX
Обнаруживается стандартными средствами: трейсами, дебаггером, профайлером. Просто если выставлена мягкая ссылка - ты нажмешь run gc в профайлере и не увидишь что от чего-то не отписался.

А использовать или не использовать мягкие ссылки:
1. Eсть ситуации, в которых отследить время, в которое надо удалить объект из словаря или отписать от события определить очень тяжело (в сущности надо будет релизовать маленкий GC на базе подсчета ссылок). Тут выбора и нет. Например видел ресурсный движок, который не заморачивался с выгрузкой ресурсов, а просто хранил все в Dictionary с мягкими ссылками (да, доверия к такой системе нет - а вдруг он через 1 секунду удалит, а нам ресурс опять потребовался - и опять грузи, т.е. нельзя настроить чтобы удалял через 30 секунд, например, но работала).
Еще где-то в ASwing в каком-то менеджере компоненты пихаются в Dictionary со слабыми сылками. Там можно было от этого избавиться, но пришлось бы использовать совсем другой подход, т.е. можно считать у них не было выбора.

2. Большинство ситуаций не такие, в них ясно, когда отписывать объект. И тут просто 2 полюса:
- отписаться, но перестраховаться слабыми ссылками
- отписаться не перестраховываясь - если уж что-то идет не так - то это надо видеть
Просто тяготею больше ко 2-му полюсу и все.

3. Не отписываться и везде слабых ссылок понавтыкать.
Чревато нагрузкой на проц.

TanaTiX 31.01.2012 15:43

Цитата:

не увидишь что от чего-то не отписался
У меня отписывание от событий уже на автомате... Как и мягкие ссылки.
1) Как-то не было у меня таких ситуаций и таких структур проектов...
2) У нас разные полюса :) Соглашусь, что оба имеют право на жизнь.
3) Это даже не вариант.


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

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