Очистка eventListeners на объекте FileReference - PullRequest
0 голосов
/ 17 июня 2010

У меня странная проблема! Я пытаюсь удалить прослушиватель событий для объекта FileReference, вызвав функцию, но, похоже, ее не удаляют, и я не понимаю, почему.

Вот код:

private function clearFileUploadListeners(file:FileReference, index:String):void {
    var dispatchEvent:Function = function(event:Event):void {
        dispatch(event.type, event, index);
    };

    file.removeEventListener(Event.COMPLETE, dispatchEvent);
    var bool:Boolean = file.hasEventListener(Event.COMPLETE);
    if (bool)
        trace("ERROR");
}

Когда я запускаю этот код, трассировка действительно происходит. Я не понимаю, почему это логическое значение возвращает true, когда я только что попытался удалить eventListener чуть выше! Наверное, я делаю что-то действительно глупое, потому что это кажется странной ошибкой.

Я надеюсь, что кто-то может помочь мне в этом вопросе.

EDIT:

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

private function upload(file:FileReference, index:String):void {
    var dispatchEvent:Function = function(event:Event):void {
        dispatch(event.type, event, index);
    };

    file.addEventListener(Event.COMPLETE, dispatchEvent);
}

Проблема в том, что мне нужно получить доступ к этой «индексной» переменной из прослушивателя, и я не могу установить ее как глобальную переменную, поскольку каждый файл имеет свой собственный индекс, и это бремя, если мне нужно расширять каждый класс событий отслеживать индекс (Event, ProgressEvent, ..). Я надеюсь, что кто-то может помочь мне в этом.

EDIT2:

Я действительно нашел временное решение, я не уверен, что оно лучшее! Я поместил свой метод removeListener фактически в метод загрузки, но сделал его переменной. Поскольку AS3 допускает динамический объект, я прикрепил этот метод к одному из моих объектов, и поэтому я просто вызываю ссылку на метод, когда это необходимо. Событие фактически удалено. Это хорошее решение, пожалуйста?

Большое спасибо, Rudy

Ответы [ 2 ]

1 голос
/ 17 июня 2010

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

Каждый раз, когда вызывается функция upload, онасоздает новое замыкание и присваивает ссылку на него переменной dispatchEvent, которая затем передается классу addEventListener.Таким образом, каждый раз, когда вызывается upload, он использует новое, другое замыкание в вызове addEventListener.Точно так же в функции clearFileUploadListeners новое замыкание создается при каждом вызове (который каждый раз имеет один и тот же код, но не тот же объект функции).Вызов removeEventListener ничего не делает, если данный обратный вызов не был добавлен в качестве прослушивателя событий для данного события, как здесь.

Чтобы решить вашу проблему, вам нужно сохранить ссылку назамыкание, которое вы передаете функции addEventListener.Таким образом, вы можете получить ссылку на то же самое замыкание, которое было добавлено, когда вам нужно будет удалить его позже в clearFileUploadListeners.

Вы можете попробовать что-то вроде следующего кода (не проверено):

import flash.utils.Dictionary;

var callbackRegistry:* = new Dictionary();


private function upload(file:FileReference, index:String):void {
    var dispatchEvent:Function = generateFileUploadCompleteCallback();

    callbackRegistry[file] = dispatchEvent;

    file.addEventListener(Event.COMPLETE, dispatchEvent);
}

private function clearFileUploadListeners(file:FileReference, index:String):void {
    var dispatchEvent:Function = callbackRegistry[file];
    callbackRegistry[file] = null;

    file.removeEventListener(Event.COMPLETE, dispatchEvent);

    var bool:Boolean = file.hasEventListener(Event.COMPLETE);
    if (bool)
        trace("ERROR");
    else
        trace("YAY, ALL OK!");
}

private function generateFileUploadCompleteCallback(index:String):Function {
    return function(event:Event):void {
        dispatch(event.type, event, index);
    };
}
0 голосов
/ 23 августа 2013

Две другие вещи, которые стоит отметить по этому вопросу.

Если вы должны использовать нативное событие напрямую, тогда вам следует всегда убедиться и использовать эти три последних необязательных параметра:

myObject.addEventListener( Event.COMPLETE, myFunction, false, 0, true );

Проверьте сообщение Гранта Скиннера на эту тему здесь: http://gskinner.com/blog/archives/2006/07/as3_weakly_refe.html

И самая лучшая практика из всех - ВСЕГДА (всерьез всегда) использовать Сигналы Роберта Пеннера (вместо пользовательских событий) и его NativeSignals (для упаковки необходимых родных событий Flash).

В пять раз быстрее, чем родные события Flash. Всегда в безопасности со слабыми ссылками. Любое количество напечатанных полезных данных в каждом сигнале.

Получите SWC здесь: https://github.com/robertpenner/as3-signals

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

signalBtnClicked.removeAll();

или

signalBtnClicked.addOnce( function( e : MouseEvent ) : void { /* do stuff */ } );

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

...