对于XMLLoader类的静态方法?如何引发Event.COMPLETE功能后返回的XML数据?静态、功能、方法、数据

2023-09-08 14:41:30 作者:超级帅气自带特效的小可爱

我试图用静态 LOAD 方法建立一个通用的XMLLoader类,意图用它如下...

I am attempting to build a generic XMLLoader class with a static LOAD method, with the intent to use it as follows...

private var _data:XML = XMLLoader.LOAD("path/to/xml_file.xml");

然后,我可以在任何客户端使用它,去到城镇使用E4X。

Then I could use it in any client and go-to-town with e4x.

普遍的问题我有是与URLLoader的完成事件,这必然调用不同的函数来设置XML数据。 这是$ P $从能够从 LOAD 方法返回的XML pventing我,因为数据被设置的之外的该功能。很显然,我需要等待完成事件,以确保数据是可用的。

The general problem I am having is with the URLLoader's COMPLETE event, which necessarily calls a different function to set the XML data. This is preventing me from being able to return the XML from the LOAD method, since the data is being set outside that function. Obviously I need to wait for the COMPLETE event in order to make sure the data is available.

不过,我觉得,也许,我可以创建并返回一个 _waitForData 函数,该函数递归调用自身,直到_data设置,然后返回数据。但它似乎是多余的(因为引发Event.COMPLETE 是这样做反正),我尝试过的方式产生一个堆栈溢出错误。

I though, perhaps, I could create and return a _waitForData function, which recursively calls itself until the _data is set, then returns the data. But it seems redundant (since Event.COMPLETE is doing that anyway), and the way I tried it generates a stack overflow error.

下面有我的尝试:

public class XMLLoader {

    private static var _url:String = "";
    private static var _data:XML = null;

    public static function LOAD(url:String):XML {

        _url = url;
        var _xmlLoader:URLLoader = new URLLoader();
            _xmlLoader.addEventListener(Event.COMPLETE, _setData);
            _xmlLoader.load(new URLRequest(_url));

        return _waitForData();
    }

    static function _setData(e:Event):void {
        XML.ignoreWhitespace = true;
        _data = new XML(e.target.data);
    }

    static function _waitForData():XML {

        if( _data == null ) {
             _waitForData();
        }

        return _data;
    }

    public function LoadXML() {}

}

我pretty的新递归函数的概念,所以我有我错误地执行我的_waitForData功能的感觉(如果它甚至是一个好主意的话)。

I pretty new to the concept of recursive functions, so I have a feeling I implemented my _waitForData function incorrectly (if its even a good idea at all).

我会AP preciate使用静态方法以这种方式任何指针,以及是否有什么我试图做的是可能的......似乎是个好主意,我认为。

I would appreciate any pointers on using static methods in this way, and whether what I am trying to do is possible...seems like a good idea I think.

推荐答案

您不想去的所有静态路由。这是一个烂摊子,复杂的事情,而不需要,是很难十个分量,如果你想装载两个XMLS在同一时间是什么? (提示:你不能)。

You don't want to go the all static route. It's a mess, complicates things without need, is hard to mantain and what if you want to load two xmls at the same time? (hint: you can't).

您是最好创建一个普通类,你想要做什么(加载XML和调度一个事件或调用的结果的函数)。然后,您可以添加的简单的界面为你调用code;如果这是一个静态函数用作一个一行,就这样吧。该功能可以被看作是一种工厂的发起创建该类的一个实例,并且还启动装载操作设定结果回调,都在一个步骤(从呼叫者角度)

You are better off creating a regular class that does what you want (load an xml and dispatch an event or call a function with the results). Then, you may add a simpler interface for your calling code; if that's a static function to be used as a one-liner, so be it. This function could be seen as a kind of factory that initiates creates an instance of the class and also initiates the load operation sets the result callback, all in one step (from the caller perspective)

我在想的东西沿着这些路线(只写和编译的罚款;没有彻底测试,但应该足以让这个想法)

I'm thinking something along these lines (just wrote it and compiles fine; haven't tested it thoroughly, but should be enough to give the idea).

package
{
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.events.IOErrorEvent;
    import flash.events.SecurityErrorEvent;
    import flash.net.URLLoader;
    import flash.net.URLRequest;
    import flash.utils.Dictionary;

    public class XMLLoader extends EventDispatcher
    {
        private var _loader:URLLoader;
        private var _data:XML;
        private var _callback:Function;

        private static var _map:Dictionary = new Dictionary();

        public function XMLLoader(callback:Function = null)
        {
            _data = null;
            _callback = callback;
            _loader = new URLLoader();
            _loader.addEventListener(IOErrorEvent.IO_ERROR,handleError);
            _loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR,handleError);
            _loader.addEventListener(Event.COMPLETE,handleComplete);
        }

        public function load(request:URLRequest):void {
            _loader.load(request);  
        }

        private function dispatchError():void {
            cleanUp();  
            dispatchEvent(new Event(Event.COMPLETE));
            if(_callback is Function) {
                _callback(null);
            }
        }

        private function dispatchSuccess():void {
            cleanUp();  
            dispatchEvent(new Event(Event.COMPLETE));
            if(_callback is Function) {
                _callback(_data);
            }
        }

        private function handleError(e:Event):void {
            dispatchError();
        }

        private function handleComplete(e:Event):void {
            var success:Boolean = false;
            try {
                _data = new XML(e.target.data);
                success = true;
            } catch(err:TypeError) {
                success = false;
            } finally {
                if(success) {
                    dispatchSuccess();
                } else {
                    dispatchError();
                }
            }
        }

        public function get data():XML {
            return _data;
        }

        private function cleanUp():void {
            if(_loader) {
                _loader.removeEventListener(IOErrorEvent.IO_ERROR,handleError);
                _loader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR,handleError);
                _loader.removeEventListener(Event.COMPLETE,handleComplete);
            }
            if(_map[this]) {
                delete _map[this];
            }
        }

        public static function loadXml(url:String,callback:Function):XMLLoader {
            var loader:XMLLoader = new XMLLoader(callback);
            loader.load(new URLRequest(url));
            //  pin down the instance just to be safe; I've seen loaders being collected...
            _map[loader] = true;
            return loader;
        }

    }
}

使用:

    private function handleResult(data:XML):void {
        if(data) {
            trace(data);
        } else {
            trace("failed");
        }
    }


    private function test():void {
        XMLLoader.loadXml("your.xml",handleResult);
    }

另外,你可以切换使用实例方法,如果你需要更多的灵活性:

Alternatively, you could switch to use the instance methods, if you need more flexibility:

    private function test():void {
        var loader:XMLLoader = new XMLLoader(handleResult);
        loader.load(new URLRequest("your.xml"));        
    }

本示例实现可以使用回调或事件。为简单起见,我只是定义一个回调函数;你可以告诉我们,如果加载操作succeded通过检查收到的数据;零意味着失败。另外,我分派Event.COMPLETE事件信号装完(即使它失败)装载机;再次,你可以知道,如果它失败或通过检查数据属性succeded。如果你愿意,你可以使用自定义事件和/或定义错误回调,但我认为你想有一个更简单的越好接口,所以我想这应该是足够了。

This sample implementation could be used with callback or events. For simplicity I'm just defining one callback function; you could tell if the loading operation succeded by checking the data you receive; null means it failed. Also, I'm dispatching an Event.COMPLETE event to signal the loader finished loading (even if it failed); again, you could know if it failed or succeded by checking the data property. You could use custom events if you want and/or define a fault callback, but I think you want a simpler as possible interface, so I think this should be enough.