我跟着previous question的示例,我正在使用加载器加载外部swf,并在加载器事件处理程序中我试图将loader.content
转换为我的自定义类PanelReferenceClip
它扩展了MovieClip
发布时我收到此错误:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
为了确保并测试swf位置是否正确并且实际上正在加载swf,我将内容的类型更改为as MovieClip
并且它工作正常。
编辑:我还想补充一点,这些swfs存储在本地,而不是通过互联网,多个网络或服务器传输。
我不确定我是否在课堂上做了一些古怪的事情,所以我提供了自定义课程的来源PanelReferenceClip
package com.components
{
import com.UI.DevicePanel;
import flash.display.MovieClip;
/**
* ...
*
* used to store the loaded swf inside the panel
*
* *parentPanel is set so that it is able to access it's parent Panel when needing
* to set parameters.
*/
public class PanelReferenceClip extends MovieClip
{
private var _parentPanel:DevicePanel;
private var _bg_mc:MovieClip;
private var _oldY:Number = 0;
private var _oldX:Number = 0;
private var _IsDragging:Boolean = false;
public function PanelReferenceClip() {
super();
}
/*--------------------------------------------------------------------------
* GETTERS AND SETTERS
* -----------------------------------------------------------------------*/
public function set parentPanel(p:DevicePanel):void {
_parentPanel = p;
}
public function get parentPanel():DevicePanel {
return _parentPanel;
}
public function get bg_mc():MovieClip {
try {
return getChildByName("bg_mc") as MovieClip;
} catch (e:Error) {
trace("could not find bg_mc in " + _parentPanel.DeviceName + " panel");
}
return null;
}
public function set oldY(n:Number):void {
_oldY = n;
}
public function get oldY():Number {
return _oldY;
}
public function set oldX(n:Number):void {
_oldX = n;
}
public function get oldX():Number {
return _oldX;
}
public function set IsDragging(b:Boolean):void {
_IsDragging = b;
}
public function get IsDragging():Boolean {
return _IsDragging;
}
}
}
这是另一个类的一部分,它正在加载swfs,然后尝试将它们分配为类PanelReferenceClip
的类prop _reference。我这样做是因为我能够得到swf和它的孩子,因为当你导入swf时你不能设置导入的swf的实例名称。所以我正在为它分配一个扩展MovieClip
的自定义类,以便我可以存储一些自定义属性。
private function handleLoad(e:Event):void
{
e.target.removeEventListener(Event.COMPLETE, handleLoad, false);
// keep reference to the content
_reference = e.target.content as PanelReferenceClip;
// ** BREAKS ON THE NEXT LINE **/
trace(_reference.numChildren);
// add loader to the display list so we can see the external SWF.
addChild(e.target.loader);
// signal the sim engine that the swf has loaded
// and to go ahead and wire up the components
dispatchEvent(new DataEvent(DataEvent.COMPLETE));
initPanel();
}
以下是用于加载swf的方法。我在应用程序上下文部分添加了尝试,但我仍然没有到达任何地方。
public function loadSWF(theSWF:String):void
{
var url:String = theSWF;
var urlReq:URLRequest = new URLRequest(url);
_urlError = url;
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, handleLoad);
_loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
var context:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain);
_loader.load(urlReq,context);
_loader.mouseEnabled = false;
}
答案 0 :(得分:1)
所提供的事实并不是决定性的,因为加载器SWF和加载外部SWF的位置非常重要。
我的猜测:您加载的内容位于不同的ApplicationDomain中。请参阅LoaderContext.applicationDomain和第二个参数Loader.load()方法。
关于力学的一些细节。显然,您将PanelReferenceClip类编译为两个不同的SWF文件。当您加载一些带有代码的外部SWF文件时,VM根据您提供的加载器上下文决定是否将任何传入声明与加载器SWF的混合声明混合。如果您指定的上下文允许混合,则传入的SWF使用与父SWF具有的重合限定名称相同的声明。如果不是 - 即使它们的完全限定名称相同,初始化的类也是不同的。在后一种情况下,您将无法将加载的内容转换为您喜欢的内容。
在handleLoad()
方法中尝试以下测试:
trace(getQualifiedClassName(e.target.content)); // This is the incoming declaration
trace(getQualifiedClassName(PanelReferenceClip)); // This is the parent declaration
即使输出相同,也不一定意味着类是相同的。如果您使用某种调试器,可以查看以下测试行中的内存地址。
var incomingClass:Class = e.target.content["constructor"];
var residentClass:Class = PanelReferenceClip;
trace(incomingClass == residentClass); // toggle breakpoint here and compare memory addresses
答案 1 :(得分:1)
如@nox-noctis所述,问题可能是由于applicationDomain引起的。我回答了similar question here。
问题的根本原因是实际上为PanelReferenceClip
定义了两个不同的类。尽管他们可能具有相同的名称,并且包含相同的代码,但Flash将它们视为两个不同的对象。
如果你给这两个不同的名字,这将更清楚地表达这些类在Flash中的表现方式。本质上,您告诉Flash将一种对象类型转换为其他类型,例如:
var foo:Foo = new Foo();
var bar:Bar = foo as Bar(); // where Bar does not inherit Foo
虽然可以使用的是将面板设置为MovieClip
,因为面板确实扩展了MovieClip。这样可以将它添加到显示列表中,但不会为面板的实现提供API。
一种解决方案是为类指定接口。这告诉Flash即使代码可能不同,这两个类也可以以相同的方式使用。这样做的好处是,您只需要将接口编译到父SWF中,而不是整个类,从而减少父文件的大小。
面板的界面可能如下所示:
public interface IPanelReference
{
function set parentPanel(p:IDevicePanel):void;
function get parentPanel():IDevicePanel;
function get bg_mc():MovieClip;
function set oldY(n:Number):void;
function get oldY():Number;
function set oldX(n:Number):void;
function get oldX():Number;
function set IsDragging(b:Boolean):void;
function get IsDragging():Boolean;
}
将界面应用于面板,如下所示:
public class PanelReferenceClip extends MovieClip implements IPanelReference
{
...
}
然后父节点将通过接口和已知的祖先引用加载的类:
private function handleLoad(e:Event):void
{
...
_reference = e.target.content as IPanelReference;
trace((_reference as DisplayObjectContainer).numChildren);
trace(_reference.oldX);
addChild(_reference as DisplayObject);
....
}
答案 2 :(得分:1)
这可能是由无法进行类型转换的类型之间的转换引起的。该变量将变为null,而不是在执行someVariable as OtherClass
时发生错误。 (示例)
我会将对原始movieclip的引用存储为PanelReferenceClip中的某个属性,并在需要访问.numChildren
//MovieClips are subclasses of Sprites... this conversion works
var originalMC:MovieClip = new MovieClip();
var sprite:Sprite = originalMC as Sprite;
trace("sprite: " + sprite); //defined
//Sprites are not subclasses of MovieClips... this conversion wont work
var originalSprite:Sprite = new Sprite();
var mc:MovieClip = originalSprite as MovieClip;
trace("mc: " + mc); //null
//MovieClips are not subclasses of PanelReferenceClips (quite the opposite)
//this conversion wont work, just as the one before
var panelRef:PanelReferenceClip = originalMC as PanelReferenceClip;
trace("panelRef: " + panelRef); //null