Все, кто пользовался
mx.utils.Delegate +
mx.events.EventDispatcher, скорее всего слышали про анти-паттерн "неиспользуемый слушатель". это известная ошибка в проектировании, не только во флэше, Макс и Майк писали про это пару раз на
novemberain.comDelegate.create() создает новую функцию и возвращает на неё ссылку. Ссылок на созданную функцию этот класс не сохраняет. Проблема возникает тогда, когда мы создаём делегированную функцию для обработки события. Чаще всего можно встретить такой код:
1
источникСобытий.addEventListener("имяСобытия", Delegate.create(получательСобытий, функцияОбработчик));
В результате этого действия ссылки на
делегирующую функцию в явном виде нигде не остается, а слушателем является именно она, а не функцияОбработчик. И удалить такого слушателя становится проблематично (а часто никто и не заботится об этом).
Решения проблемы, которые встречаются чаще всего, связаны с запоминанием ссылок на делегатов для последующего удаления. А это вызывает кучу лишней мороки, поскольку нужно где-то хранить ссылки, не забывать вовремя удалять их и т. п.
Для случая удаления слушателя из функции-обработчика, есть решение куда проще. Такая ситуация встречается очень часто: при срабатывании обработчика нужно отписаться от получения событий.
Делегирующая функция вызывает
делегируемую. При этом слушателем является
делегирующая. Хвала ECMA, при вызове любой функции ей доступна ссылка
arguments.caller, которая является ссылкой-на-того-кто-вызвал-меня. Более того, поскольку мы говорим о сочетании
EventDispatcher +
Delegate, функция-обработчик всегда получает ссылку на истоник событий и на имя события в виде свойств
eventObject.target и
eventObject.typeТаким образом, у нас внутри функцииОбработчика есть все необходимые ссылки для операций со слушателем. Если необходимо удалить слушателя изнутри обработчика, можно сделать так:
1
2
3
4
5
6
7
8
function делегируемаяФункцияОбработчик(eventObject:Object):Тип
{
var eventSource:Object = eventObject["target"];
var eventName:String = eventObject["type"];
// !
eventSource.removeEventListener(eventName, arguments.caller);
}