2008-10-07 11 views
15

He intentado hacer esto:ActionScript 3.0 utilizando cierres para controladores de eventos

root.addEventListener("click", 
    function() 
    { 
     navigateToURL(ClickURLRequest,"_self"); 
    }); 

Y se le añade el detector de eventos. Me gusta usar cierres porque funcionan bien en esta situación,

embargo

, retirar el detector de eventos requiere una referencia a la función original, y que no uso un cierre anónima, que no funciona, he intentado:

root.removeEventListener("click", 
     function() 
     { 
      navigateToURL(ClickURLRequest,"_self"); 
     }); 

así como:

root.removeEventListener("click", function() {}); 

la única manera que encontré fue que iba a funcionar para deshacerse del cierre anónimo y señalar los detectores de eventos a una función preexistente:

function OnClick (e:Event) 
{ 
    navigateToURL(ClickURLRequest,"_self"); 
} 

root.addEventListener("click", OnClick); 
root.removeEventListener("click", OnClick); 

¿Alguien sabe una manera de utilizar los cierres anónimos por controladores de eventos al tiempo que conserva la capacidad para eliminarlos?

+0

¿Por qué no usa weakReference? –

Respuesta

3

Se puede pensar en la palabra clave function() como un constructor, la creación de un nuevo objeto (un cierre) cada vez. Por lo tanto, si crea el cierre solo como parámetro y no conserva una referencia en ningún lugar, no hay forma de obtener el cierre "igual" en otro lugar.

La solución obvia es lo que no te gusta, definiendo la función antes de usarla. Por supuesto, todavía puede ser un cierre completo y no solo una función 'estática'. simplemente defínalo en el contexto que desee y asígnelo a una variable local.

+0

Sí, estoy de acuerdo con Javier. Si no conserva la referencia, no puede eliminar esa función. –

0

no estoy seguro de si esto va a funcionar, pero su digno de un tiro:

root.removeEventListener("click", arguments.callee); 

Más información al respecto se puede encontrar Flex lang ref

+0

No JustFoo, esto no funciona. –

36

Esta es una forma genérica de la eliminación de los detectores de eventos que he utilizado en proyectos de producción


addEventListener 
(
    Event.ACTIVATE, 
    function(event:Event):void 
    { 
     (event.target as EventDispatcher).removeEventListener(event.type, arguments.callee)    
    } 
) 
+0

En segundo lugar esto. También tenga en cuenta que ha cometido un error tipográfico en el ejemplo: "argumnts" – hasseg

+0

whoops my bad, se ha solucionado ahora;) –

+0

Brilliant! Nunca hubiera pensado en eso yo mismo. – Martin

0

No es demasiado diferente de usar una función definida, pero quizás esto satisfaga sus necesidades. Recuerde que las funciones son objetos de primera clase en ActionScript y que puede almacenarlas y pasarlas como variables.

 
protected function addListener() 
{ 
    m_handler = function(in_event:Event) { removeEventListener(MouseEvent.CLICK, m_handler); m_handler=null} 
    addEventListener(MouseEvent.CLICK, m_handler) 
} 
protected var m_handler:Function 
0

Sólo una nota en su código que me encontré en el Flex en un conjunto de Semana de tutoriales en el sitio web de Adobe. Allí, dijeron que siempre debes usar las constantes para los tipos de eventos en lugar de la cadena. De esa forma obtendrás protección contra errores tipográficos. Si crea un error tipográfico en el tipo de evento cadena (como por ejemplo "clse"), su controlador de eventos se registrará pero, por supuesto, nunca se invocará. En su lugar, use Event.CLOSE para que el compilador detecte el error tipográfico.

-1

I no sabe lo que está haciendo en realidad, pero en este ejemplo particular, tal vez usted podría tener una variable global _clickEnabled.

Luego dentro del controlador de eventos que acaba de comprobar _clickEnabled, y si su falsa que acaba de return inmediatamente.

A continuación, puede activar y desactivar el evento en general sin desmontar y volver a conectarlo.

0

Me encontré haciendo esto mucho, así que probé esto. Parece que funciona bien.

addSelfDestructiveEventListener('roomRenderer', 'complete', trackAction, 'floorChanged'); 

private function addSelfDestructiveEventListener(listenee:*, event:String, functionToCall:Function, StringArgs:String):void 
{ 
    this[listenee].addEventListener(event, function(event:Event):void 
     { 
      (event.target as EventDispatcher).removeEventListener(event.type, arguments.callee); 
      functionToCall(StringArgs); 
     }) 
} 
2

utilizo esto a veces:

var closure:Function = null; 
root.addEventListener("click", 
    closure = function() 
    { 
     navigateToURL(ClickURLRequest,"_self"); 
    }); 

root.removeEventListener("click", closure); 
7

Como ya se ha sugerido, es posible retirar el cierre de la cadena de oyentes desde dentro del propio cierre. Esto se hace mediante el uso de arguments.callee:

myDispatcher.addEventListener("click", function(event:Event):void 
{ 
    IEventDispatcher(event.target).removeEventListener(event.type, arguments.callee); 

    // Whatever else needs doing goes here 
}); 

Esto a su vez de manera efectiva el cierre en un oyente de una sola vez del evento, sólo tiene que desprenderse una vez que el evento ha disparado. Aunque es sintácticamente detallado, es una técnica increíblemente útil para los muchos eventos que realmente solo se disparan una vez (o que solo te importan una vez) como "creationComplete" en Flex, por ejemplo. Utilizo esto todo el tiempo cuando descargo datos, ya que creo que tener el código de devolución de llamada en línea hace que sea más fácil de entender. Es como esconder la distancia asíncrono-dad:

myLoader.addEventListener("complete", function(event:Event):void 
{ 
    /* Even though the load is asynchronous, having the callback code inline 
    * like this instead of scattered around makes it easier to understand, 
    * in my opinion. */ 
}); 

Sin embargo, si desea escuchar los eventos en múltiples ocasiones, esto no va a ser muy eficaz por razones obvias. En ese caso, debe almacenar una referencia al cierre en alguna parte. Los métodos son objetos como cualquier otra cosa en ActionScript y se pueden pasar. Por lo tanto, podemos modificar nuestro código para tener este aspecto:

var closure:Function; 

myDispatcher.addEventListener("click", function(event:Event):void 
{ 
    closure = arguments.callee; 

    // Whatever else needs doing goes here 
}); 

Cuando tenga que quitar el detector de eventos, utilice la referencia de 'cierre', así:

myDispatcher.removeEventListener("click", closure); 

Obviamente, esta es una ejemplo abstracto, pero usar cierres como este puede ser bastante útil. Sin embargo, tienen inconvenientes, como ser menos eficientes que los métodos nombrados. Otro inconveniente es el hecho de que en realidad tiene que almacenar una referencia al cierre si alguna vez lo necesita. Se debe tener cuidado para preservar la integridad de esa referencia, al igual que con cualquier otra variable.

Por lo tanto, aunque la sintaxis diferente puede tener sus usos, no siempre es la mejor solución. Es un tipo de cosas de manzanas y naranjas.

Cuestiones relacionadas