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.

API Design

Walking Tall