0

J'ai un problème étrange! J'essaie de supprimer un écouteur d'événement sur un objet FileReference en appelant une fonction, mais il semble ne pas être supprimé, et je ne comprends pas pourquoi.Effacement d'eventListeners sur un objet FileReference

Voici le code:

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"); 
} 

Quand je lance ce code, la trace se passe réellement. Je ne comprends pas pourquoi ce booléen retourne vrai, quand j'ai juste essayé d'enlever le eventListener juste au-dessus! Je suppose que je fais probablement quelque chose de vraiment stupide parce que cela semble être une erreur étrange.

J'espère que quelqu'un peut m'aider s'il vous plaît sur cette question.

EDIT:

Je crois qu'il doit faire avec le fait que la fonction dispatchEvent est définie dans une autre fonction quand j'ajoute l'auditeur:

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); 
} 

Le problème est que je dois accéder à cette "index" variable de l'écouteur, et je ne peux pas le définir comme une variable globale car chaque fichier a son propre index et c'est un fardeau si je dois étendre chaque classe d'événement pour garder une trace de l'index (Event, ProgressEvent,. .). J'espère que quelqu'un peut m'aider s'il vous plaît à ce sujet.

EDIT2:

En fait, je trouve une solution temporaire, je ne sais pas si c'est le meilleur! J'ai mis ma méthode removeListener à l'intérieur de la méthode upload, mais je l'ai transformée en variable. Comme AS3 permet l'objet dynamique, j'ai attaché cette méthode à l'un de mes objets, et donc j'appelle simplement la référence à la méthode si nécessaire. L'événement est réellement supprimé. Est-ce une bonne solution s'il vous plaît?

Merci beaucoup, Rudy

Répondre

1

Vous avez raison, il faut faire avec le fait que vous définissez une fonction dans une autre fonction, puis l'utiliser pour gérer les événements.

Chaque fois est appelée la fonction upload, il crée une nouvelle closure, et attribue une référence à la variable à dispatchEvent, qui est ensuite transmis à la classe addEventListener. Donc, chaque fois que upload est appelé, il utilise une nouvelle fermeture, dans l'appel à addEventListener. De même, dans la fonction clearFileUploadListeners, une nouvelle fermeture est créée à chaque appel (qui arrive à avoir le même code à chaque fois, mais n'est pas le même objet fonction). L'appel à removeEventListener ne fait rien si le rappel donné n'a pas été ajouté en tant qu'écouteur d'événement pour l'événement donné, ce qui est le cas ici.

Pour résoudre votre problème, vous devez stocker une référence à la fermeture que vous passez à la fonction addEventListener. De cette façon, vous pouvez obtenir une référence à la même fermeture qui a été ajoutée lorsque vous devez l'enlever plus tard dans clearFileUploadListeners.

Vous pouvez essayer quelque chose le long des lignes du code ci-dessous (non testé):

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

Merci beaucoup, super explication claire, je comprends. J'aime votre solution, elle est très proche de celle que j'avais en tête (j'ai défini une fonction removeListeners() dans ma fonction de téléchargement, et l'ai stockée dans un objet). IE: object.var = removeListeners; then object.var(); C'est semblable au vôtre, je n'ai pas besoin de garder la trace d'un dictionnaire mais plutôt d'utiliser la pile. Merci de votre aide! – Rudy

+0

Heureux d'avoir aidé :-) – Cameron

0

Deux autres choses à noter à ce sujet.

Si vous devez utiliser un événement natif directement alors vous devriez à peu près toujours assurez-vous et utiliser ces trois derniers paramètres optionnels:

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

Vérifiez le poste de Grant Skinner sur le sujet ici: http://gskinner.com/blog/archives/2006/07/as3_weakly_refe.html Et la meilleure pratique consiste à TOUJOURS (sérieusement toujours) utiliser les Signals de Robert Penner (au lieu des événements personnalisés) et ses NativeSignals (pour envelopper les événements Flash natifs nécessaires).).

Cinq fois plus rapide que les événements natifs de Flash. Toujours sûr avec des références faibles. N'importe quel nombre de données utiles typées dans chaque signal.

Obtenez le SWC ici: https://github.com/robertpenner/as3-signals

Les signaux ont été conçus pour résoudre le problème même que vous rencontrez. Imaginez au lieu de créer un tableau et la gestion que pour supprimer tous les auditeurs si vous pouviez appeler:

signalBtnClicked.removeAll(); 

ou

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

Sachant que la fermeture que vous venez de créer sera immédiatement déréférencé une fois qu'il est appelé et heureusement aller nuit nuit quand le GC fait ses tours.

Questions connexes