Monday, June 29, 2009

ArgumentError: Error #2505 (AS3, Flash 9, Loader)

I've been meaning to post about this error for awhile. You can find solutions on the web, but they seem very buried... hence all the key words in my title.

The error appears in Flash 9 when you use a loader more than once and try to add the e.target.content to the DisplayList after each load. If you are running Flash 10, you will not see the error... The biggest lesson I took from this error is to continue to test on older versions of Flash. If you set your publish settings to Flash 9, but have Flash 10 downloaded on your machine.... you still need to test your site on a machine with Flash 9. Pain in the arse, but worth it if it means catching errors before the client.

Anyways, back to the error at hand, you have a class loader that has been initiated and you plan on using it for your photo gallery. The first image loads just fine and in the completeHandler you add the image (e.target.content) to the stage using addChild and casting the content as some sort of display object. The second image loads just fine, but in the completeHandler at the line where you call "addChild" and error #2505 will get thrown saying that "The supplied DisplayObject must be a child of the caller".

Hmmph. It worked once, why would it fail?

It has something to do with Flash 9's Loader keeping a reference of its content even after the content has been added to a new parent. A quick and dirty fix to the problem is to make a new Loader for every item you are loading. That worked for my needs, however you may want to be careful with memory and garbage collection if you are loading an intense number of images.

Omar Faleh suggests either casting the content as a DisplayObject and unloading the loader or making a copy of the BitmapData and using the copy instead of the content.

Ed had his 2505 errors occurring when he called "unload()" after adding the e.target.content to the displayList. He suggests adding the Loader to the stage instead of the content. So you would add just "e.target" INSTEAD OF "e.target.content" to the display list.

In any case, there are plenty of work-a-rounds. The important thing is to be aware of the issue and make sure you continue to test your sites on older versions of Flash... even if your personal computer runs on 10.

8 comments:

Iain said...

Why re-use the loader at all when you can make a new one? I try not to reuse any objects as it can make a project more "stateful" and so less stable.

Ickydime said...

@Iain
My thought process is that Object creation is costly (performance and memory) and that Flash is single threaded so it would never need more than one loader at a time.

I am surprised you say you don't resuse any objects... Pooling and reusing objects is much more efficient than creating new ones.

Andre Anaya said...

Check my post about this issue.
http://blog.andreanaya.com/lang/en/2009/03/loader-issue/

here is the solution

function onLoadComplete(e:Event):void{
var image:Bitmap = e.currentTarget.content;
loader.unload();
addChild(image);
}

Ickydime said...

@Andre
That is definitely the cleanest solution I've seen yet. I didn't realize that unload did not kill the child... I had assumed we had to add the child to the display list before unload and not just save a reference of it.

But after checking API it is clear:

--------------
unload(): Removes a child of this Loader object that was loaded by using the load() method. The property of the associated LoaderInfo object is reset to null. The child is not necessarily destroyed because other objects might have references to it; however, it is no longer a child of the Loader object.
--------------

Thanks for the solution!

Josh Tynjala said...

"Flash is single threaded so it would never need more than one loader at a time"

ActionScript is single-threaded, but Flash Player has multiple threads. Multiple Loaders can load their content simultaneously. That means you can get your content faster, assuming the network stack used by Flash Player allows you to open the number of connections you need. If not, your requests will just get queued.

Ickydime said...

@Josh
I'll have to go back and test some loaders out. Maybe it was my network, but for some reason in a previous project I tried to start a bunch of loaders at once so I could capture the bytesTotal of multiple files and they would get queued and only trickle in one at a time.

Have you been able to get onProgress events from 2 different loaders before one completes?

Iain said...

@Ickydime - Object creation is costly in the context of 1000 particles exploding, but really I don't see how a couple of loaders is going to make any difference. My philosophy is to leave optimisation until I know it's actually needed.

Ickydime said...

@josh
Looks like you are right. You can have multiple loaders going at once. Very cool. Stumbled across this guy: http://code.google.com/p/bulk-loader/ Altho, not sure any project I have now would need it since its 20 some k to load.

@iain
good point... admittedly I sometimes get caught up in optimization practices even when they aren't needed. guess they got ingrained in me from my previous boss and previous life... doing simulation visualizations, everything was about optimization and how much we could squeeze out of the code.