Не думаю, что это ошибка. Это скорее проблема связи.
Ошибка верификатора не возникает, когда вы пытаетесь создать экземпляр B
. Это происходит, как только ваш основной swf загружается и проверяется плеером. Это важное различие. Чтобы понять, что я имею в виду, измените этот код:
var bar:B = new B();
to
var bar:B;
Вы по-прежнему будете получать сообщение об ошибке.
Я не знаю, как вы создаете swf, но из ошибки кажется очевидным, что класс A
(родитель B
) исключается из swf. Я могу воспроизвести это с помощью этого переключателя mxmlc:
-compiler.external-library-path "lib.swc"
Однако изменив его на:
-compiler.library-path "lib.swc"
Проблема уходит. Очевидно, что этот вид побеждает цель загрузки ресурсов во время выполнения, поскольку эти ресурсы уже скомпилированы в ваш main.swf (на самом деле, это хуже, потому что, сделав это, вы только что увеличили глобальный размер загрузки вашего приложения) .
Итак, если вы установите свою художественную библиотеку как внешнюю, компилятор сможет выполнять проверку типов, вы получите автозаполнение в вашей среде IDE и т. Д. Однако ваш класс B
по-прежнему зависит от определения A
. Итак, во время выполнения A
должен быть определен всякий раз, когда B
впервые упоминается в вашем коде. В противном случае верификатор обнаружит несогласие и взорвется.
Во Flash IDE, когда вы связываете символ, есть опция «экспорт в первом кадре». Именно так ваш код экспортируется по умолчанию, но это также означает, что можно отложить, когда игрок впервые ссылается на определение класса. Flex использует это для предварительной загрузки. Он загружает только крошечный бит swf, достаточный для отображения анимации предварительного загрузки, в то время как остальная часть кода (который не «экспортируется в первом кадре») и ресурсы загружаются. Делать это вручную кажется немного обременительным, если не сказать больше.
Теоретически использование RSL должно помочь здесь, если я правильно помню, как работает RSL (идея заключается в том, что RSL должен загружаться игроком прозрачно). По моему опыту, RSL - это настоящая боль, и она не стоит того (просто чтобы назвать несколько раздражающих «особенностей»: вам нужно жестко запрограммировать URL-адреса, довольно сложно сделать недействительными кеши, когда это необходимо, и т. Д. Возможно, некоторые из проблем с RSL ушли, и сейчас эта штука работает разумно, но я могу сказать вам, что работаю с Flash, начиная с Flash 6 и на протяжении многих лет, время от времени я развлекался идеей использования RSL (потому что сама идея дает много смысла, реализация в стороне), только чтобы отказаться от нее после обнаружения одной проблемы за другой.
Возможность избежать этой проблемы (вообще без использования RSL) может заключаться в наличии shell.swf, который загружает art.swf и после его загрузки загружает ваш текущий код. Поскольку к моменту загрузки вашего code.swf art.swf уже загружен, верификатор найдет com.foo.graphics.A
(в art.swf) при проверке com.foo.graphics.B
(в code.swf).
public function Shell()
{
loadSwf("art.swf",onArtLoaded);
}
private function loadSwf(swf:String,handler:Function):void {
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, handler);
var request:URLRequest = new URLRequest(swf);
var context:LoaderContext = new LoaderContext();
context.applicationDomain = ApplicationDomain.currentDomain;
loader.load(request, context);
}
private function onArtLoaded(e:Event):void {
loadSwf("code.swf",onCodeLoaded);
}
private function onCodeLoaded(e:Event):void {
var li:LoaderInfo = e.target as LoaderInfo;
addChild(li.content);
}
В вашем текущем основном классе добавьте этот код:
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
Переместите логику конструктора (если есть) в метод init
, и он должен работать нормально.
Но что мне не нравится в этом подходе, так это то, что вам нужно создать другой проект для оболочки.
Как правило, у меня есть класс, который проксирует графический ресурс.
private var _symbol:MovieClip;
public function B() {
var symbolDef:Class = ApplicationDomain.currentDomain.getDefinition("com.foo.graphics.A") as Class;
_symbol= new symbolDef();
addChild(_symbol);
}
Поскольку com.foo.graphics.A
- это просто графический ресурс, вам действительно не нужно проксировать другие вещи. Я имею в виду, что если вы хотите изменить x
, y
, width
и т. Д. И т. Д., Вы можете просто изменить эти значения в прокси-сервере, и на практике результат будет таким же. Если в каком-то случае это не так, вы можете добавить геттер / сеттер, который фактически действует на проксируемый объект (com.foo.graphics.A
).
Вы можете абстрагировать это в базовый класс:
public class MovieClipProxy extends MovieClip {
private var _symbol:MovieClip;
public function MovieClipProxy(linkagetName:String) {
var symbolDef:Class = ApplicationDomain.currentDomain.getDefinition(linkagetName) as Class;
_symbol = new symbolDef();
addChild(_symbol);
}
// You don't actually need these two setters, but just to give you the idea...
public function set x(v:Number):void {
_symbol.x = v;
}
public function get x():Number {
return _symbol.x;
}
}
public class B extends MovieClipProxy {
public function B() {
super("com.foo.graphics.A");
}
}
Кроме того, внедрение домена приложения в качестве зависимости (и перемещение механизма создания экземпляра в другой служебный класс) может быть полезно для некоторых проектов, но приведенный выше код подходит в большинстве ситуаций.
Единственная проблема с этим подходом заключается в том, что имя связи в конструкторе B
не проверяется компилятором, но, поскольку оно находится только в одном месте, я думаю, что с этим можно справиться. И, конечно же, вы должны убедиться, что ваша библиотека ресурсов загружена, прежде чем пытаться создать экземпляр класса, который зависит от нее, иначе он покажет ожидание. Но в остальном это сработало для меня довольно хорошо.
PS
Я только что понял, что в вашем текущем сценарии это может быть более простое решение:
public class B extends MovieClip {
private var _symbol:MovieClip;
public function B() {
_symbol = new A();
addChild(_symbol);
}
}
Или просто:
public class B extends MovieClip {
public function B() {
addChild(new A());
}
}
Та же идея с прокси, но вам не нужно беспокоиться о создании экземпляра объекта из строки с использованием домена приложения.
person
Juan Pablo Califano
schedule
26.06.2010