我有一个奇怪的问题!我试图通过调用一个函数来删除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时!我想我可能正在做一些非常愚蠢的事情,因为这似乎是一个奇怪的错误。
我希望有人可以帮我解决这个问题。
编辑:
我认为这与我在添加监听器时在另一个函数中定义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方法实际放在upload方法中,但是把它变成了一个变量。由于AS3允许动态对象,我将此方法附加到我的一个对象,因此我只需在必要时调用对该方法的引用。该事件实际上已被删除。这是一个很好的解决方案吗?
非常感谢, 鲁迪
答案 0 :(得分:1)
你是对的,它与你在另一个函数中定义函数,然后用它来处理事件这一事实有关。
每次调用函数upload
时,它都会创建一个新的closure,并将其引用分配给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);
};
}
答案 1 :(得分:0)
关于这个主题还有两点需要注意。
如果您必须直接使用本机事件,那么您应该总是确保并使用这最后三个可选参数:
myObject.addEventListener( Event.COMPLETE, myFunction, false, 0, true );
在此处查看Grant Skinner关于此主题的帖子: http://gskinner.com/blog/archives/2006/07/as3_weakly_refe.html
最好的做法是始终(总是)始终使用Robert Penner的Signals(而不是自定义事件)和他的NativeSignals(包装所需的原生Flash事件)。
比Flash的原生事件快五倍。 使用弱引用始终安全。 每个信号中的任意数量的有效载荷。
在这里获取SWC: https://github.com/robertpenner/as3-signals
信号旨在解决您遇到的问题。 想象一下,如果您只是调用:
,而不是创建一个数组并管理它以删除所有侦听器signalBtnClicked.removeAll();
或
signalBtnClicked.addOnce( function( e : MouseEvent ) : void { /* do stuff */ } );
知道你刚刚创建的闭包一旦被调用就会被立即取消引用,并且很快就会在GC进行巡视时过夜。