U⁄A LABO

RSS

SEARCH

AUTHOR

  • KNOCKKNOCK (10件)小遣い2万円のフラッシュデベロッパー。
    帰りが遅いのにキレる嫁をだましだまし制作中・・・。

  • TAKAIW (13件)フラッシュデベロッパー。遊びでゲームを作るのも好きです。外見に似合わないイラストを描くのも好きです。とにかく作るのが好きです。

  • CHIKATHREESIX (8件)メタル界のフラッシュデベロッパー。またある時はメタルギタリスト。オーサリング中もヘッドバンギングは絶やさない。

  • YANBOU (6件)犬と猫で、家が毎日運動会のフラッシュデベロッパー。
    ビールから発泡酒へ変更で節約中。

  • AKUZE (2件)2003年からユナイティアに寄生しているフラッシュデベロッパー。
    シルクドソレイユとカナダが好き。

  • DECO-DEKAI (1件)ビートダウンパートでご飯何杯も食べられます。
    ハードコア・テクニカルディレクターを目指して日々精進。

CATEGORY

HOME  >  Loaderの使いまわしについて

2009.03.25 CHIKATHREESIX

Loaderの使いまわしについて

ついにオープンしたUA-LABO!
どうもchikathreesixです。

AS3でloaderをクラスのプロパティに持って使いまわす際にハマったので書いておきます。

まず以下ソースは一度画像を読み込んで表示し、3秒後にまた別の画像を読み込んで表示するプログラムです。
これを実行すると、loaderのloadメソッドを実行する際に「ArgumentError: Error #2025: 指定した DisplayObject は呼び出し元の子でなければなりません。」というエラーが出てしまいます。
public class LoaderTest extends Sprite 
{
	private var _loader:Loader;
	private var _img:DisplayObject;
		
		
	public function LoaderTest() {
		_loader = new Loader();
		_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, _loadedImg);
		_loader.load(new URLRequest("sample1.jpg"));
			
			
		var timer:Timer = new Timer(3000, 1);
		timer.addEventListener(TimerEvent.TIMER_COMPLETE, _completeAction);
		timer.start();
	}
		
		
	private function _loadedImg(e:Event):void
	{
		_img = _loader.content;
		addChild(_img);
	}
		
		
	private function _completeAction(e:TimerEvent):void {			
		_loader.load(new URLRequest("sample2.jpg"));
	}
}

まず簡単な解決法は以下の二つになります。
①_loader.contentをaddChildせずにloaderをaddChildする。
②_loader.load()を実行する前に、_loader = new Loader()として、インスタンスを生成しなおす。

ですが、loaderのcontentプロパティを抜き出していろいろ操作したい場合①の解決法は使えず、②の解決法ではインスタンスを生成し直してしまうので、あまり良いとは思えません。

インスタンスを生成し直すとうまくいくということなので、とりあえずunloadしてみました。
private function _loadedImg(e:Event):void
{
			
	_img = _loader.content;
	_loader.unload();
	addChild(_img);
}
なんとあっさりうまくいきました。以下TAKAIW先生による考察です。
 
考察①:loadメソッド内でloaderのcontentプロパティがremoveChildされていて、それに対して「ArgumentError: Error #2025: 指定した DisplayObject は呼び出し元の子でなければなりません。」というエラーが出ているのではないか。
イメージで言うと以下のような感じでしょうか。
public class Loader extends DisplayObjectContainer{
	...
	public load(request:URLRequest, context:LoaderContext = null):void 
		if(this.content != null && this.contains(this.content)) this.removeChild(this.content);
		...
	}
}
おそらく読み込みが完了した時点でloaderはcontentプロパティを自身にaddChildするのでしょう。なので、loaderを使用するクラスでloader自身をaddChildする場合や、addChildをまったく行わない場合はランタイムエラーが出ないものと思われます。


考察②:unloadでは何らかの初期化処理とremoveChildが行われているのではないか。

実際以下のようにすると同様のエラーが出てしまいます。
private function _loadedImg(e:Event):void
{		
	_img = _loader.content;
	addChild(_img);
	_loader.unload();
}
これもおそらくcontentプロパティをremoveChildする際にエラーがでているのではないでしょうか。しかしこの場合このあとのloadはきちんと実行されています。ということは、何らかの初期化処理はremoveChildの前に行われているのではないかという推測ができます。
そこでTAKAIW先生より目から鱗アドバイス。
「try-catchしてみ」
やってみます。
private function _loadedImg(e:Event):void
{	
	_img = _loader.content;
	addChild(_img);
			
	try {
		loader.unload();
	}catch (e) {
	}
}
できました。。なぜ??
TAKAIW先生「removeChildでthrowされるから最初の初期化処理はうまくいくんだよ」
なるほど、ということで何らかの初期化処理がされてから、removeChildされているということがわかりました。
try-catchはあまり使ってませんでしたが、その利便性に驚かされました。
これからはどんどん使いたいですね。

最後に、これだけ長々と書きましたがなんとCS4ではランタイムエラーが出ずにうまくいってしまいます。というのもplayer10だとうまくいくからみたいです。
ということは、CS4で作っててなにも問題ないプログラムがplayer9の環境で見ると突然動かなくなるという可能性がある、ということですね。
今回の事例のようなものが他にもあると考えると、気をつける必要がありそうですね。

CATEGORY