— boreal-kiss.com

FileReferenceオブジェクトと変数のスコープの関係

これは知らないとはまる。Filereferenceオブジェクトへの参照をローカル変数の受け渡しで扱っている場合注意が必要。ローカル変数のみを使用する場合ロードが中断される可能性がある。Flash Player 10 (Astro)のAPIはまだ日本語になっていないようだったので以下を引用するが同じことがFilereference.load()にもあてはまる。

FileReference オブジェクトがスコープ外に移動した場合、そのオブジェクトに対して完了していないアップロードまたはダウンロードは、スコープから離れた時点でキャンセルされます。アップロードまたはダウンロードの続行を期待できる限りは、FileReference オブジェクトがスコープ内にあることを確認してください。

Adobe® Flex™ 3 リファレンスガイド

以下にFileRefarence.load()が正しく完了する場合と完了しない場合の二種類の例を挙げる。どちらも”Load”ボタンを押すとローカルから画像を選択できるようになり、画像を選択するとステージにその画像が表示されるという構造になっている。両者の違いはFilereferenceオブジェクトを扱う変数がローカル変数のみかそうではないかだけである。

FileReference.load()が成功する場合

FileReferenceオブジェクト変数をクラスプロパティで定義しているため(_fr)クラスファイル内でFilereferenceオブジェクトのスコープがはずれることはない。そのためボタンクリックでローカルから選択された画像はFileReference.load()で正しくロードされキャンバス(_canvas)に表示される。

<!-- FileReference.load()が正しく完了する例 -->
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
    
    <mx:Button label="Load" click="onClick(event)"/>
    <mx:Canvas id="_canvas"/>

    <mx:Script>
        <![CDATA[
            import flash.net.FileReference;
            
            //クラスプロパティとして定義
            private var _fr:FileReference;
            
            private function setListeners(target:FileReference):void{
                var fr:FileReference = target as FileReference;
                fr.addEventListener(Event.SELECT,onSelect);
                fr.addEventListener(Event.COMPLETE,onComplete);
            }
            
            private function onClick(e:Event):void{
                _fr = new FileReference();
                setListeners(_fr);
                _fr.browse();
            }
            
            //関数を抜けてもFileReferenceオブジェクトへの参照"_fr"はスコープ内
            //そのため関数を抜けてもFileReference.load()は続行される
            private function onSelect(e:Event):void{
                var fr:FileReference = e.target as FileReference;
                fr.load();
            }
            
            private function onComplete(e:Event):void{
                var fr:FileReference = e.target as FileReference;
                var loader:Loader = new Loader();
                loader.loadBytes(fr.data);
                loader.contentLoaderInfo.addEventListener(Event.INIT,onInit);
            }
            
            private function onInit(e:Event):void{
                _canvas.rawChildren.addChild(e.target.content);
            }
        ]]>
    </mx:Script>
</mx:Application>

FileReference.load()が失敗する場合

一方、以下の場合FileReferenceオブジェクト変数はローカル変数でしか定義されておらず、Filereferenceオブジェクトのスコープが完全にはずれる箇所がある(onSelect()を抜けた直後)。その時点でFileReference.load()はキャンセルされるためロード完了によるEvent.COMPLETEが発動しない(_canvasに画像が表示されまでに至らない)。

<!-- FileReference.load()が途中でキャンセルされる例 -->
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
    
    <mx:Button label="Load" click="onClick(event)"/>
    <mx:Canvas id="_canvas"/>

    <mx:Script>
        <![CDATA[
            import flash.net.FileReference;
            
            private function setListeners(target:FileReference):void{
                var fr:FileReference = target as FileReference;
                fr.addEventListener(Event.SELECT,onSelect);
                fr.addEventListener(Event.COMPLETE,onComplete);
            }
            
            private function onClick(e:Event):void{
                //ローカル変数として定義
                var fr:FileReference = new FileReference();
                setListeners(fr);
                fr.browse();
            }
            
            //関数を抜けるとFileReferenceオブジェクトへの参照がスコープ外になる
            //そのため関数を抜けるとFileReference.load()は完了前にキャンセルされる
            private function onSelect(e:Event):void{
                trace(e);
                var fr:FileReference = e.target as FileReference;
                fr.load();
            }
            
            private function onComplete(e:Event):void{
                var fr:FileReference = e.target as FileReference;
                var loader:Loader = new Loader();
                loader.loadBytes(fr.data);
                loader.contentLoaderInfo.addEventListener(Event.INIT,onInit);
            }
            
            private function onInit(e:Event):void{
                _canvas.rawChildren.addChild(e.target.content);
            }
        ]]>
    </mx:Script>
</mx:Application>
1 comment
  1. […] Filereferenceオブジェクトの参照方法について補足。参照している変数が(全て)スコープ範囲外に移動すると、FileReference.load()などの一部のメソッドは途中キャンセルされる。詳しくはFileReferenceオブジェクトと変数のスコープの関係 – boreal-kiss.comを参照ください。 […]

Submit comment