【问题标题】:Call function problems as3as3调用函数问题
【发布时间】:2015-11-17 15:44:39
【问题描述】:

我正在从一个子类调用一个函数并将当前部分变量传递给它,然后加载/删除下一部分,一切正常,直到我尝试将相同的变量传递给我之前使用的核心函数。我不明白为什么它不再工作了。

以下问题:

1180:调用可能未定义的方法 setupSection。

  • 最初我设置参数并从标准函数加载类:

    public function setupVariables():void {
        //Main code here
    
        //Establish Section 
        currentSection = secData;
        setupSection(currentSection);
    }
    
    public function setupSection(sectionHolder:String):void {
        //Here selects the right choice from an Array and loads new Section.
    }
    
    //I call the function from the child
    Main.changeSection("loadNext");
    
    
    public static function changeSection(lSection:String):void {
        var lSection : String;
        currentSection = lSection;
    
        trace("Val Passed = " +currentSection);
        //TraceOutput is - Val Passed = loadNext
    
        setupSection(currentSection);
    }
    
    public function setupSection(sectionHolder:String):void {
        //LoadSection etc. . .
    }
    

有问题的命令似乎是这样的:

setupSection(currentSection);

currentSection 是之前设置的 String。

我以前用过这个,它工作得很好,但不是来自静态函数。

如果有人能解释为什么这不起作用,我将不胜感激,因为我无法让它起作用。

【问题讨论】:

  • 你应该重新考虑你的设计。混合静态和非静态函数总是会带来麻烦。静态属性和函数是独立于实例的,这意味着类XYZ 的对象不需要具有能够访问它的静态属性/函数的实例。这实际上意味着,您正试图从无到有地调用一个函数。为什么不从您的子类中调度一个事件,而不是静态函数调用?
  • @DodgerThud - 正如你所说,我可能对这个问题过于关注了,以前从主类调用的函数不能通过另一个函数调用似乎是不合理的相同的代码。调度我遇到问题的事件,但我会调查它。我想控制主类的主导航以在关键类之间进行选择。加载这些关键类将为这些子类中的每一个的单独类和单独部分提供导航。从每个关键类中,都有一个选项可以在关键类之间进行更改。不知道怎么做。
  • in the same code 你看,这就是问题所在,它不是同一个代码。一个在静态上下文中(全局可用),一个在对象上下文中。今天晚些时候,当我下班时,我将尝试对这个问题进行更彻底的解释。
  • @DodgerThud - 谢谢,我已经添加了一些来更好地解释我在哪里以及如何称呼它。
  • 您的代码格式不正确,您能修复一下吗?还有这个“子类”的名称是什么?

标签: function actionscript-3 variables parameter-passing call


【解决方案1】:

静态函数不能调用实例函数。静态本质上是全局的,与类的任何实例都没有关联,因此它不能调用实例函数,因为它不是实例并且不知道存在什么(如果有)实例。

如果您真的想将changeSection() 保留为静态函数,您可以做的是将类的实例作为参数传递,以便您可以在实例上调用setupSection()。示例:

public static function changeSection(lSection:String, main:Main):void { 
    var lSection : String; currentSection = lSection;

    trace("Val Passed = " +currentSection);
    //TraceOutput is - Val Passed = loadNext

    main.setupSection(currentSection);
}

如果您在调用函数时无法轻松访问类的实例,那么您尝试做的更像是singleton。在这种情况下,您需要存储对单个实例的静态引用,以便您可以从任何地方轻松访问它。然后您只需要实例函数,并通过对实例的静态引用来调用它们。例如:

class Main {
    public static var main:Main;
    public var currentSection:String;
    public function Main() {
        main = this;
    }
    public function changeSection(section:String):void {
        currentSection = section;
        setupSection(currentSection);
    }
    public function setupSection(section:String):void {
        // setup section
    }
}

现在您可以像现在这样在任何地方使用您的 Main 类,如下所示:

Main.main.changeSection("loadNext");

不过,我应该提一下,这通常不是一个好的设计,因为您将代码全局耦合到 Main。正如您在某种意义上已经发现的那样,这变得混乱且难以扩展。更好的解决方案是使用事件或dependency injection


使用事件需要更多设置,但从长远来看,它通常更简洁且问题更少。我从不后悔将深度耦合的代码重构为事件。

首先,您可以定义一个漂亮的小自定义事件类,告诉您某个部分应该更改(您并不总是需要自定义事件类,您可以使用通用的 Event 类,但自定义类可以让您定义事件的自定义数据):

public class SectionEvent extends Event {
    public static var SECTION_CHANGE:String = "sectionChange";
    public var section:String;
    public function SectionEvent(type:String, section:String){
        super(type, true); // bubbles=true, important later
        this.section = section;
    }
}

现在您可以监听此事件并在您的 Main 类(我假设它是一个文档类)中处理它:

class Main extends MovieClip {
    public function Main(){
        addEventListener(SectionEvent.SECTION_CHANGE, sectionChangeHandler);
    }
    private function sectionChangeHandler(event:SectionEvent):void {
        changeSection(event.section);
    }
    public function changeSection(section:String):void {
        currentSection = section;
        setupSection(section);
    }
    private function setupSection(section:String):void {
        // setup section
    }
}

现在要更改部分,只需像这样调度事件(从Main 的任何子显示对象,它会冒泡,因为我们设置了 bubbles=true):

dispatchEvent(new SectionEvent(SectionEvent.SECTION_CHANGE, "nextSection"));

希望您能看到,即使这增加了一些额外的代码,它也能更好地组织它。它使Main 看起来非常平易近人,通过事件非常清楚地描述了动作,并且不难理解和使用。流程的每个部分都是紧密的encapsulated 代码,您可以比以前更容易理解、扩展和测试。

【讨论】:

  • 你打败了我 :),我正准备写一个答案。不过有一件事,我相信setupSectionMain 内部的一个函数,所以传递孩子的实例并不能解决问题。
  • 哦,我以为他是在说changeSection 是从Main 调用的,而不是在Main 中定义的...我认为您在重新阅读后是对的。更新了我的代码示例。 (@esadude,您能否将您的类语句与您的代码一起发布,或者明确在哪里定义了哪些函数?)
  • 嗯,现在我看到@esadude 正在调用静态主函数,我明白为什么您的评论建议重新设计。传递Main 的实例可能不是他想做的。扩展我的答案...
  • 感谢您的所有输入,我理解它为什么会导致问题,在我选择的初始选项中可能存在重复。我正在查看所有输入,但使用@DodgerThud - var s:Section = //yadayada,我假设该部分是我各自的新部分是正确的。在它完全加载之前,我从孩子那里得到一个错误,所以它必须在事件上,因为它加载了正确的类来开始:错误#1069:在 flash.events.Event 上找不到属性部分名称并且没有默认值. var e:Event = new Event(Event.CHANGE); e['sectionname'] = //想要的部分? dispatchEvent(e);
  • @Aaron - 稍后我会更深入地了解您提供的内容。最初我希望在“section”变量上有一个监听器并触发该部分的加载/重新加载,但我放弃了,因为我无法让它工作。道奇的选择似乎更接近我希望可以做到的事情,但有时当你花这么长时间并且看起来很简单时,你会失去理性思考。 1 天为此摔跤,只是对一些事情变得困难而感到沮丧!
【解决方案2】:

正如@Aaron 在他的回答(以及我最初的评论)中指出的那样,静态函数/属性与类的实例无关。

为了更彻底地解释这一点,我将举一个例子。假设我们有一个名为 Main 的类和一个名为 Section 的类。

class Section extends Sprite{
    public Section(){}

    public function a():void{
        //this is a function of an instance
    }

    public static function b():void{
       //a static function of the class
       a();//this will not work
    }
}

class Main extends Sprite{
    public Main(){
        var first:Section = new Section();
        var second:Section = new Section();
    }
}

如您所见,我们的 Main 类创建了 Section 类的两个实例。对于您拥有的每个实例,都会为您的所有属性和功能在 RAM 中清除空间。所以firstsecond 在你的 RAM 中都有自己的小空间。它们还拥有一个名为a() 的函数,因为非静态函数/属性与它们的实例相关联。但是函数b() 呢?好吧,这个独立于任何实例存在,并且仅在您的 Ram 中存在 一次

所以,当你尝试做这样的事情时

first.b();

我猜你假设调用了first 实例的函数a()。但这是不可能的,因为静态函数不知道您所指的 a() 是什么,它可能是 firstsecond,因为 b() 存在于它们外部

希望我的解释很容易理解:)


但是让我们实际解决您的问题,而不需要任何静态函数。正如我的一个 cmets 中提到的,您可以(应该?)在这里使用事件。我将放弃自定义事件恶作剧,而是提供一个更简单(但更 hacky)的解决方案。

在你的 setupSection() 函数中,你可能会做这样的事情

public function setupSection(sectionHolder:String):void{
    var s:Section = //you get the appropiate child instance somehow
    addChild(s);
}

您需要做的是侦听从此实例调度的事件,如下所示:

var s:Section = //yadayada
s.addEventListener(Event.CHANGE, onSectionChange);
addChild(s);

在您的 Child 类中,当您想要更改 Section 时,不要调用静态函数,而是这样做

var e:Event = new Event(Event.CHANGE);
e['sectionname'] = //the desired section
dispatchEvent(e);

现在,在调度事件之后,将调用 Main 实例中的函数 onSectionChange。适当的功能应该是这样的

private function onSectionChange(e:Event):void{
  var sectionname:String = e['sectionname'];
  setupSection(sectionname);
}

【讨论】:

  • 哈,现在你打败了我......我刚刚用非常相似的想法编辑了我的答案。无论哪种方式,我都同意活动绝对是去这里的方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多