Code Czar

Daryl Joseph Ducharme,

Losing FileReference Scope

, , ,

I just ran into something while working with the FileReference class in AS3.
private function onUploadNewAppClick( event:MouseEvent ):void
{
  var fRef:FileReference = new FileReference();
  fRef.addEventListener( Event.SELECT, this.onUploadAppSelect );
  var appsFilter:FileFilter = new FileFilter( "Flash Applications", "*.swf" );
  fRef.browse( [appsFilter] );
}
However, the SELECT event never got fired. I have used the FileReference class quite a bit in Flash 8 and AS2, why wasn't this working. In fact, I just made something with the FileReferenceList class that was almost identical, why wasn't this working. Scope, that's why ( I'll explain below ).

"It didn't work," isn't descriptive enough. Let me tell you what was happening. My function, onUploadNewAppClick, was firing and I was getting the file browse dialog. However, when I chose a file to upload, the dialog would close and nothing would happen. When I put a trace statement in the onUploadAppSelect function, I could see that it never got fired. Hmmm, what's different than what I did before?

Let's take a look at the FileReferenceList code that worked fine:
private function onUploadClick( event:MouseEvent ):void
{
  this.fRefList = new FileReferenceList();
  this.fRefList.addEventListener( Event.SELECT, this.onFilesSelect );
  this.fRefList.browse();
}
At first the only difference I could see was the appsFilter, an implimentation that is new in AS3. So of course I took it out and tried again. Same results so I put the appsFilter back in. The other difference I saw was that in my non-working code fRef is a local variable to the onUploadNewAppClick function. In the working code, fRefList is a member variable of the class onUploadClick is a member function of. So I changed my code to this:
private function onUploadNewAppClick( event:MouseEvent ):void
{
  this.fRef = new FileReference();
  this.fRef.addEventListener( Event.SELECT, this.onUploadAppSelect );
  var appsFilter:FileFilter = new FileFilter( "Flash Applications", "*.swf" );
  this.fRef.browse( [appsFilter] );
}
Voila! It worked. But why? Looking at the live docs I came across this:

if the FileReference object goes out of scope, any upload or download that is not yet completed on that object is canceled upon leaving the scope. Be sure that your FileReference object remains in scope for as long as the upload or download is expected to continue.

I had never seen that before, even though it is in the AS2 docs as well, but that seems like the issue. Think about the way functions work.

1. Function gets called
2. Memory is allocated for all local variables
3. Function actions occur
4. Memory is unallocated for all local variables

So in the case of my first verion of the onUploadNewAppClick function fRef was in memory long enough to open the browse dialog then went out of scope. There were no other references to it so it got garbage collected. When the dialog was closed there was nothing to fire off the SELECT event. Hopefully, someone else who runs into this issue will read my post before spending to much time wondering why it doesn't work.

Scope is a wonderful and powerful thing, but when you don't fully understand it errors often occur. Hopefully, I have brought a little more understanding to you.
----
Daryl "Deacon" Ducharme is currently "Code Czar" for the Interactive Agency Provis Media Group, LLC which helps organizations enhance identity, connect with customers and increase productivity.

Walking TallAPI Design

Comments

mank1 Thursday, May 17, 2007 2:58:56 PM

Consider this guy informed.

Anonymous Monday, June 4, 2007 1:40:49 PM

olli_m writes: Saved much time by finding this hint

Anonymous Friday, June 8, 2007 2:17:21 PM

miller writes: thanks. I just spent an hour with this and your post saved me several more.

Anonymous Sunday, November 11, 2007 8:10:25 AM

jared writes: I too find myself very appreciative of this hard to track down problem. Thanks Daryl!

Anonymous Tuesday, November 20, 2007 2:21:26 PM

Adrian writes: Just thought I'd add... The upgrade to OS X 10.5 (Leopard) breaks FileReference and FileReferenceList in the Flash Player. the symptom is that all SELECT events actually fire as CANCEL. Some suggest upgrading the Flash Player but I found upgrading my OS to 10.5.1 solved the problem. The implication is that, if your application relies on this, you may need to add a check for the user's OS. Hope this is useful to someone!

Anonymous Wednesday, March 24, 2010 4:28:56 PM

RES writes: Thanks a lot, I've lost a week of work trying to solve something like this.

Anonymous Monday, April 25, 2011 5:13:52 PM

Anonymous writes: I'm still a little confused, I thought objects weren't flag for the garbage collection sweep if they had strongly referenced objects tied to them. That's why it's so important to remove event listeners when your done with them, and why you should always use this technique: http://gskinner.com/blog/archives/2006/07/as3_weakly_refe.html

How to use Quote function:

  1. Select some text
  2. Click on the Quote link

Write a comment

Comment
(BBcode and HTML is turned off for anonymous user comments.)

If you can't read the words, press the small reload icon.


Smilies