0

我有一个奇怪的问题!我试图通过调用函数来删除 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");
}

当我运行这段代码时,跟踪实际上发生了。当我试图删除上面的 eventListener 时,我不明白为什么这个布尔值返回 true!我想我可能正在做一些非常愚蠢的事情,因为这似乎是一个奇怪的错误。

我希望有人可以在这个问题上帮助我。

编辑:

我相信这与我添加侦听器时 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);
}

问题是我需要从侦听器访问这个“索引”变量,我不能将它设置为全局变量,因为每个文件都有它自己的索引,如果我必须扩展每个事件类来跟踪它是一个负担的索引(事件,ProgressEvent,..)。我希望有人可以帮助我。

编辑2:

我实际上找到了一个临时解决方案,我不确定它是否是最好的!我把我的 removeListener 方法实际上放在了上传方法中,但是把它变成了一个变量。由于 AS3 允许动态对象,我将此方法附加到我的一个对象,因此我只在必要时调用该方法的引用。该事件实际上已被删除。请问这是一个好的解决方案吗?

非常感谢你,鲁迪

4

2 回答 2

1

你是对的,这与你在另一个函数中定义一个函数,然后用它来处理事件有关。

每次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);
    };
}
于 2010-06-16T22:42:50.413 回答
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 运行时愉快地度过夜晚。

于 2013-08-23T08:36:14.980 回答