【问题标题】:How to use a method of a class inside a callback function in actionscript?如何在actionscript的回调函数中使用类的方法?
【发布时间】:2011-11-15 20:18:37
【问题描述】:

在回调函数内部调用类的方法时,不能使用this对象。
要调用该方法,在javascript中,我声明that变量,将this分配给that,并在回调中使用that来调用this的方法。

在 actionscript 中,我必须像在 javascript 中那样做吗?

以下代码是使用that 调用回调内部方法的示例。
actionscript中有没有更简单的方法?

class C {
    private var that:C;

    function C() {
        that = this
    }

    public function f1():void {
        var sp:Sprite = new Sprite;

        sp.addEventListener(MouseEvent.CLICK, function():void {
            this.f2(); // this doesn't work
            that.f2(); // that works
        });
    }

    public function f2():void {
        trace('hello');
    }
}

【问题讨论】:

  • 你为什么不省略'this'?
  • @OXMO456 非常感谢。省略 this 有效。这是非常简单的解决方案。

标签: flash actionscript-3 actionscript callback event-listener


【解决方案1】:

如果您将回调函数设为 C 类的方法,您将能够访问this

 public class C
 {
     private function f1():void
     {
         var sp:Sprite = new Sprite();

         sp.addEventListener(MouseEvent.CLICK, callback);
     }

     private function callback(event:MouseEvent):void
     {
         this.f2();
     }

     private function f2():void
     {
         trace("Hello World");
     }
}

现在this指的是类C的实例,它的作用域是整个类。

【讨论】:

  • 内联闭包是脏的,脏的内存泄漏也是如此
  • @Ivan 感谢您提供有用的信息。我不知道。如果f2() 有参数(function f2(message:String):void { trace(message); })并且如果我想将 f2('hello') 添加到 sp1 和 f2('good bye') 到 sp2 作为回调函数,我想我必须定义 2回调方法,private function callbak(event:MouseEvent):void { this.f2('hello'); }private function callbak(event:MouseEvent):void { this.f2('good bye'); }?有更好的方法吗?
  • @divillysausages 感谢您提供有关内联闭包内存泄漏的信息。如果我在 addEventListener() 之前将内联闭包分配给变量并使用该变量进行回调。比如var f:Function = function():void { that.f2(); }; sp.addEventListener(MouseEvent.CLICK, f);,这段代码是否也是内联闭包,是否会导致内存泄漏?还是干净安全?
  • @js_ 我添加了一个答案来解释为什么评论部分不够大:)
【解决方案2】:

这是另一种方法:

package some.package {
    class SomeSprite extends Sprite {
        public function f1():void
        {
            var sprite1:Sprite = new Sprite;
            sprite1.addEventListener(MouseEvent.CLICK,
                (new Closure(f2, this, ["Hello"], sprite1).handler));

            var sprite2:Sprite = new Sprite;
            sprite2.addEventListener(MouseEvent.CLICK,
                (new Closure(f2, this, ["Bye Bye"], sprite2).handler));
        }

        private function f2(message:String):void
        {
            trace(message);
        }
    }
}

class Closure {
    public var callback:Function;
    public var thisObj:Object;
    public var params:Array;
    public var dispatcher:IEventDispatcher;
    public var cleanAfterCallback:Boolean = true;

    function Closure(callback:Function, thisObj:Object, 
        params:Array, dispatcher:IEventDispatcher)
    {
        this.callback = callback;
        this.thisObj = thisObj;
        this.params = params;
        this.dispatcher = dispatcher;
    }

    public function handler(e:Event):void
    {
        callback.apply(thisObj, params);

        if (cleanAfterCallback)
            dispatcher.removeEventListener(e.type, eventHandler)
    }
}

【讨论】:

  • 如果您确实需要使用闭包,这是一个非常好的解决方案。如果不是这样,您可以创建一个自定义类 MySprite extends Sprite()。然后向这个类添加一个属性“消息”,并在方法 f1 中修改代码,如 sp1:MySprite = new MySprite(); sp1.message = "你好"; sp1.addEventListener(MouseEvent.CLICK, 回调); sp2:MySprite = new MySprite(); sp2.message = "再见"; sp2.addEventListener(MouseEvent.CLICK, 回调);现在在回调中你可以调用 f2(MySprite(event.target).message);
【解决方案3】:

请参阅 Adob​​e 网站上的 Function Documentation。使用 apply 与“thisArg”等于您要调用成员函数的对象,“this”将是正确的。

【讨论】:

  • 谢谢。但我认为apply 不能用于回调,因为apply 在回调发生时立即执行函数而不是执行函数。
  • @js_ Fearnor 的意思是我在回答中的代码 sn-p 中写的
【解决方案4】:

您正在使用内联函数闭包,因此您要查找的 this 将不在该范围内。它与 javascript 中的函数闭包非常相似(如果不相同)。上面的方法很好。还有其他方法可以做到这一点,但不一定更简单,这取决于您的实现。

function():void {
        this.f2(); // this is scoped only to within this function
        that.f2(); // that has reference to the global object this
} 

请阅读 ActionScript 文档中的以下内容
Function Closures
Event listeners

【讨论】:

    【解决方案5】:

    这不是答案,而是更多地解释了为什么内联闭包是内存泄漏,来自@js_ 的评论请求。

    Flash 中的内存管理有两种方式;引用计数以及标记和扫描(查看http://divillysausages.com/blog/tracking_memory_leaks_in_as3 以更深入地了解)。

    内存泄漏来自addEventListener() 调用。默认情况下,addEventListener 将创建对它正在侦听的对象的引用 - 例如,您的匿名函数将保存对您的对象的引用。

    您可以将其设为弱侦听器,但由于您的函数是匿名的,因此它没有其他引用,这意味着如果您的事件侦听器很弱,它会在函数结束时全部收集(如果您使用一个局部变量)。

    因此,要使匿名函数正常工作,您需要使事件侦听器变得强大。但是当你来移除监听器时,你无法访问匿名函数,所以你无法移除它。最好的情况是,您丢失了为回调分配的内存。最坏的情况是,匿名函数对对象的引用意味着对象本身永远不会被收集(可以链接),因为 Flash 认为它仍在使用中。

    如果对象本身最终没有其他引用,除了事件侦听器,那么两者都应该在标记和清除阶段被收集(因为在设计时考虑了这种循环引用)。也就是说,您永远不会真正想要标记和扫描启动 - 它非常慢(您可能会注意到程序中经常出现暂停)并且只有在您的内存使用开始失控时才会开始。你想自己控制引用计数

    【讨论】:

    • 谢谢。以下2个避免标记和清除的想法怎么样? (1)我认为用null或其他对象覆盖sp,例如sp.addEventListener(MouseEvent.CLICK, function():void { that.f2(); }); sp = null; or sp = anotherSprite;也删除了对匿名函数的引用而不调用removeEventListener()。 (2) 我可以在 addEventListener() 之后访问匿名函数,方法是将其关联到 sp 的成员而不是一个 just 变量,例如,sp.f = function():void { that.f2(); }; sp.addEventListener(MouseEvent.CLICK, sp.f);sp.removeEventListener(sp.f);
    • 如果你将函数存储在sp.f 之类的地方,那么它就不再是匿名的了;)不过这是一般的想法。在我的所有课程中,我实现了一个 destroy() 函数,在该函数中我清除侦听器、空引用、清除数组、字典、从舞台上删除图形、在任何实现它的内部对象上调用 destroy() 等等。每个对象都负责因为它自己清理。因此,在您的示例中,它类似于 sp.destroy(); sp = null; 我提供的链接中有一个 MemoryTracker 类,可帮助您查看对象是否正确消失
    【解决方案6】:

    如果你做一个跟踪(这个),它会说类似[function Global]的东西。这就是它不起作用的原因。

    【讨论】:

      猜你喜欢
      • 2011-04-19
      • 2011-12-01
      • 1970-01-01
      • 2010-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-31
      • 1970-01-01
      相关资源
      最近更新 更多