Home > Tags > tips

tips

enhance Flex Builder

EclipseでのFlex開発をより便利にしたい。

きっかけはThe Flash Blogのエントリーです。
New tutorial on customizing Flex Builder
More Snip Tree View features!
FlashTest Eclipse Plugin Alpha
Pimp My Eclipse - Part 1
Pimp My Eclipse - Part 2
Pimp My Eclipse - Part 3

Eclipse起動時のスプラッシュも自分で描くというUIへの強いこだわりが感じられます。
最初は読み流してましたが、途中から記事がパート化して評判も良いようなので僕も試してみようと。

まず手始めに、TextMateに似た強力なスニペット機能をEclipseに追加します。
環境はEclipse 3.4.1(Pleiadesで日本語化済み)、Flex Builder Plugin 3.0.2。

Continue reading

efficient as3 part2

efficient as3の続きのエントリです。

Tips on how to write efficient AS3 - part 2の簡単な意訳。

Array push vs. Array index
pushを使ってはいけない。値をセットする時はlist[list.length] = data;のようにしよう。配列の長さは外部変数に保存して、要素を追加/削除した時はその変数をインクリメント/デクリメント。

//コメント欄でのBlizzさんの指摘:list[list.length - 1] = data;だよね?
//返事:Blizzが正しいよ。ありがとう!

Array emptying - length 0 vs. A new Array
配列を空にするにはlengthプロパティを0にするのが、新しく配列を生成する必要もなくてかつメモリも節約できて良い方法だと考えるかもしれない。でもそれは(ほとんどのケースで)速くないよ。lengthプロパティを使って速くなるのは、一度に510個以上の配列をクリアする必要がある時だ。

Var declarations on multiple lines vs. Var declarations on a single line
数個の変数を宣言する時は、一行で書いた方が少しだけ効率的だよ。

var a:int=0, b:int=0, c:int=0;
vs.
var a:int=0;
var b:int=0;
var c:int=0;

この項目については、コメント欄や外部リンクにてバイトコードやメモリ使用量にまで話が及んだ熱いやり取りが行われていました。追いかけて読んでみると楽しいです。

Using Xor to swap variables
値を交換する時に3つ目の変数を作りたくない時は、

a = a^b;
b = a^b;
a = a^b;

のようにすると、

var oldB:int = b;
b = a;
a = oldB;

よりも300%ほど速くなるよ。

Multiplication vs. Division
割り算より掛け算の方が約130%速いよ。5000/1000 より 5000*0.001。

Type casting comparison
型をキャストする時はasを使った方がType(item)よりも250%速いよ。でもどちらも使わなければ1400%ほど速くてビビった。

Long vs Short variable names
この項目は論争の余地がある。なぜならこれを実践すると可読性の低いコードになるからね。短い変数は1つのループ内で1000回反復して1ミリ秒速くなる程度。でも僕はこれがコード最適化の最後の切り札だと考えてるよ。

この元の記事ではコメント欄も併せて読むといいと思います。

ちなみに最初の項目は僕も試してみました。
ヒルベルト曲線のクラスでは、drawPath()を使うためにVectorにひたすら値をpushしてましたが、

data.push(pt.x + dx);
data.push(pt.y + dy);
       ↓↓↓
data[iter++] = pt.x + dx;
data[iter++] = pt.y + dy;

のように変更して10次のヒルベルト曲線を書いてみると、

・data.push():2142ms
・data[iter++]:1837ms

となり少し高速化しました。(関連:Hilbert Curve - Flex(AS3.0))
とりあえず参考までに。

ObjectUtil.getClassInfo - Flex

ActionScriptでクラスの情報を得るには、flash.utils.describeTypeメソッドを使いますが、Flexの場合だと、mx.utils.ObjectUtilgetClassInfoメソッドでも簡易情報を取得できます。

前回のヒルベルト曲線のクラスをdescribeTypeとObjectUtil.getClassInfoの2つのメソッドでクラス情報を取得してみると、

describeType()

<type name="Hilbert" base="flash.display::Shape" isDynamic="false" isFinal="false" isStatic="false">
  <extendsClass type="flash.display::Shape"/>
  <extendsClass type="flash.display::DisplayObject"/>
  <extendsClass type="flash.events::EventDispatcher"/>
  <extendsClass type="Object"/>
  <implementsInterface type="flash.display::IBitmapDrawable"/>
  <implementsInterface type="flash.events::IEventDispatcher"/>
  <constructor>
    <parameter index="1" type="int" optional="false"/>
    <parameter index="2" type="uint" optional="false"/>
  </constructor>
  <variable name="data" type="__AS3__.vec::Vector.&lt;Number>"/>
  <accessor name="graphics" access="readonly" type="flash.display::Graphics" declaredBy="flash.display::Shape"/>
  <accessor name="scaleZ" access="readwrite" type="Number" declaredBy="flash.display::DisplayObject"/>
  <accessor name="accessibilityProperties" access="readwrite" type="flash.accessibility::AccessibilityProperties" declaredBy="flash.display::DisplayObject"/>
  <accessor name="scrollRect" access="readwrite" type="flash.geom::Rectangle" declaredBy="flash.display::DisplayObject"/>
  <accessor name="rotationZ" access="readwrite" type="Number" declaredBy="flash.display::DisplayObject"/>
  <accessor name="height" access="readwrite" type="Number" declaredBy="flash.display::DisplayObject"/>
  <method name="getBounds" declaredBy="flash.display::DisplayObject" returnType="flash.geom::Rectangle">
    <parameter index="1" type="flash.display::DisplayObject" optional="false"/>
  </method>
  <accessor name="blendShader" access="writeonly" type="flash.display::Shader" declaredBy="flash.display::DisplayObject"/>
  <accessor name="opaqueBackground" access="readwrite" type="Object" declaredBy="flash.display::DisplayObject"/>
  <accessor name="alpha" access="readwrite" type="Number" declaredBy="flash.display::DisplayObject"/>
  <accessor name="cacheAsBitmap" access="readwrite" type="Boolean" declaredBy="flash.display::DisplayObject"/>
  <method name="local3DToGlobal" declaredBy="flash.display::DisplayObject" returnType="flash.geom::Point">
    <parameter index="1" type="flash.geom::Vector3D" optional="false"/>
  </method>
  <accessor name="x" access="readwrite" type="Number" declaredBy="flash.display::DisplayObject"/>
  <accessor name="visible" access="readwrite" type="Boolean" declaredBy="flash.display::DisplayObject"/>
  <accessor name="y" access="readwrite" type="Number" declaredBy="flash.display::DisplayObject"/>
  <accessor name="scaleX" access="readwrite" type="Number" declaredBy="flash.display::DisplayObject"/>
  <method name="globalToLocal3D" declaredBy="flash.display::DisplayObject" returnType="flash.geom::Vector3D">
    <parameter index="1" type="flash.geom::Point" optional="false"/>
  </method>
  <accessor name="mouseX" access="readonly" type="Number" declaredBy="flash.display::DisplayObject"/>
  <method name="hitTestPoint" declaredBy="flash.display::DisplayObject" returnType="Boolean">
    <parameter index="1" type="Number" optional="false"/>
    <parameter index="2" type="Number" optional="false"/>
    <parameter index="3" type="Boolean" optional="true"/>
  </method>
  <accessor name="scaleY" access="readwrite" type="Number" declaredBy="flash.display::DisplayObject"/>
  <accessor name="z" access="readwrite" type="Number" declaredBy="flash.display::DisplayObject"/>
  <accessor name="mouseY" access="readonly" type="Number" declaredBy="flash.display::DisplayObject"/>
  <accessor name="parent" access="readonly" type="flash.display::DisplayObjectContainer" declaredBy="flash.display::DisplayObject"/>
  <accessor name="mask" access="readwrite" type="flash.display::DisplayObject" declaredBy="flash.display::DisplayObject"/>
  <method name="getRect" declaredBy="flash.display::DisplayObject" returnType="flash.geom::Rectangle">
    <parameter index="1" type="flash.display::DisplayObject" optional="false"/>
  </method>
  <accessor name="rotation" access="readwrite" type="Number" declaredBy="flash.display::DisplayObject"/>
  <accessor name="width" access="readwrite" type="Number" declaredBy="flash.display::DisplayObject"/>
  <method name="localToGlobal" declaredBy="flash.display::DisplayObject" returnType="flash.geom::Point">
    <parameter index="1" type="flash.geom::Point" optional="false"/>
  </method>
  <method name="globalToLocal" declaredBy="flash.display::DisplayObject" returnType="flash.geom::Point">
    <parameter index="1" type="flash.geom::Point" optional="false"/>
  </method>
  <accessor name="transform" access="readwrite" type="flash.geom::Transform" declaredBy="flash.display::DisplayObject"/>
  <accessor name="blendMode" access="readwrite" type="String" declaredBy="flash.display::DisplayObject"/>
  <accessor name="root" access="readonly" type="flash.display::DisplayObject" declaredBy="flash.display::DisplayObject"/>
  <accessor name="name" access="readwrite" type="String" declaredBy="flash.display::DisplayObject"/>
  <accessor name="loaderInfo" access="readonly" type="flash.display::LoaderInfo" declaredBy="flash.display::DisplayObject"/>
  <accessor name="scale9Grid" access="readwrite" type="flash.geom::Rectangle" declaredBy="flash.display::DisplayObject"/>
  <accessor name="filters" access="readwrite" type="Array" declaredBy="flash.display::DisplayObject"/>
  <accessor name="rotationX" access="readwrite" type="Number" declaredBy="flash.display::DisplayObject"/>
  <method name="hitTestObject" declaredBy="flash.display::DisplayObject" returnType="Boolean">
    <parameter index="1" type="flash.display::DisplayObject" optional="false"/>
  </method>
  <accessor name="stage" access="readonly" type="flash.display::Stage" declaredBy="flash.display::DisplayObject"/>
  <accessor name="rotationY" access="readwrite" type="Number" declaredBy="flash.display::DisplayObject"/>
  <method name="toString" declaredBy="flash.events::EventDispatcher" returnType="String"/>
  <method name="addEventListener" declaredBy="flash.events::EventDispatcher" returnType="void">
    <parameter index="1" type="String" optional="false"/>
    <parameter index="2" type="Function" optional="false"/>
    <parameter index="3" type="Boolean" optional="true"/>
    <parameter index="4" type="int" optional="true"/>
    <parameter index="5" type="Boolean" optional="true"/>
  </method>
  <method name="hasEventListener" declaredBy="flash.events::EventDispatcher" returnType="Boolean">
    <parameter index="1" type="String" optional="false"/>
  </method>
  <method name="dispatchEvent" declaredBy="flash.events::EventDispatcher" returnType="Boolean">
    <parameter index="1" type="flash.events::Event" optional="false"/>
  </method>
  <method name="removeEventListener" declaredBy="flash.events::EventDispatcher" returnType="void">
    <parameter index="1" type="String" optional="false"/>
    <parameter index="2" type="Function" optional="false"/>
    <parameter index="3" type="Boolean" optional="true"/>
  </method>
  <method name="willTrigger" declaredBy="flash.events::EventDispatcher" returnType="Boolean">
    <parameter index="1" type="String" optional="false"/>
  </method>
</type>

ObjectUtil.getClassInfo()

(Object)#0
  alias = ""
  dynamic = false
  metadata = (null)
  name = "Hilbert"
  properties = (Array)#1
    [0] (QName)#2
      localName = "accessibilityProperties"
      uri = ""
    [1] (QName)#3
      localName = "alpha"
      uri = ""
    [2] (QName)#4
      localName = "blendMode"
      uri = ""
    [3] (QName)#5
      localName = "cacheAsBitmap"
      uri = ""
    [4] (QName)#6
      localName = "filters"
      uri = ""
    [5] (QName)#7
      localName = "graphics"
      uri = ""
    [6] (QName)#8
      localName = "height"
      uri = ""
    [7] (QName)#9
      localName = "loaderInfo"
      uri = ""
    [8] (QName)#10
      localName = "mask"
      uri = ""
    [9] (QName)#11
      localName = "mouseX"
      uri = ""
    [10] (QName)#12
      localName = "mouseY"
      uri = ""
    [11] (QName)#13
      localName = "name"
      uri = ""
    [12] (QName)#14
      localName = "opaqueBackground"
      uri = ""
    [13] (QName)#15
      localName = "parent"
      uri = ""
    [14] (QName)#16
      localName = "root"
      uri = ""
    [15] (QName)#17
      localName = "rotation"
      uri = ""
    [16] (QName)#18
      localName = "rotationX"
      uri = ""
    [17] (QName)#19
      localName = "rotationY"
      uri = ""
    [18] (QName)#20
      localName = "rotationZ"
      uri = ""
    [19] (QName)#21
      localName = "scale9Grid"
      uri = ""
    [20] (QName)#22
      localName = "scaleX"
      uri = ""
    [21] (QName)#23
      localName = "scaleY"
      uri = ""
    [22] (QName)#24
      localName = "scaleZ"
      uri = ""
    [23] (QName)#25
      localName = "scrollRect"
      uri = ""
    [24] (QName)#26
      localName = "stage"
      uri = ""
    [25] (QName)#27
      localName = "transform"
      uri = ""
    [26] (QName)#28
      localName = "visible"
      uri = ""
    [27] (QName)#29
      localName = "width"
      uri = ""
    [28] (QName)#30
      localName = "x"
      uri = ""
    [29] (QName)#31
      localName = "y"
      uri = ""
    [30] (QName)#32
      localName = "z"
      uri = ""

どうやらgetClassInfo()ではパブリックプロパティのQNameが返ってくるようです。
AS3.0の場合だとE4Xがあるので、describeType()の方がまだ使えますね。
getClassInfo()の方はどういうときに便利に利用できるのか思いつきません。。

Binding - Flex

Flexのバインディングで試したこと。記事にするほどのことじゃないんですけど。

TextInputの内容を相互にバインディングしたら無限ループする、、わけないよなぁと思って書いてみたらやっぱりしませんでしたという話。

<mx:TextInput id="TextInputA" text="{TextInputB.text}"/>
<mx:TextInput id="TextInputB" text="{TextInputA.text}"/>

2つのテキストインプットそれぞれに文字を入れてみてください↓

ソースが変更されたときに1回だけトリガされるんですね。
こんな所で開発者が無限ループの心配する必要はなく、そこはFlexがちゃんとやってくれると。
親切。

SWFの複製 - Flex

Loaderクラスを使って外部SWFをロードするサンプルはたくさんありますが、今回はLoaderとByteArrayを利用してStageにロード済みのSWFを複製します。

ここで肝になるのはLoaderInfoクラスです。

LoaderInfo クラスは、ロードされる SWF ファイルやイメージファイル (JPEG、GIF、PNG ファイルなど) に関する情報を提供します。LoaderInfo オブジェクトは、すべての表示オブジェクトで使用できます。提供される情報には、ロードの進行状況、ロードする側とロードされたコンテンツの URL、メディアの総バイト数、メディアの規格高さと幅などが含まれます。

複製の手順は以下の通りです。
1. DisplayObject(SWFやロードされたImage)のloaderInfoプロパティからバイト情報を取得(ByteArrayに格納)
2. Loader.loadBytes()でそのバイト情報を読み込む
3. LoaderオブジェクトのcontentLoaderInfoプロパティにアクセスしてロード状況を監視
4. ロードが完了したらLoaderをaddChild

バイト情報を取得するには、loaderInfo.bytesで取得できます。
ただし、FlashPlayerのバージョンが9.0.115.0からじゃないと使えないので注意!
Flex2のリファレンスには載ってませんでした。なのでFlex3.0以降で。

下の図にもあるように、LoaderInfoオブジェクトは、ロードされたオブジェクトファイルとロードした Loader オブジェクト間で共有されているようです。

ロードされたSWFの複製をFlexで行う場合の例を以下に示します。

Imageコンポーネント(Img)にロードされたSWFを別のImageコンポーネント内(DupImg)に複製

<mx:Image id="Img" width="200" height="200" source="starjulia.swf" />
<mx:Image id="DupImg" width="200" height="200" />

<mx:ApplicationControlBar width="100%">
  <mx:Button label="Duplicate" click="{this.duplicateImg()}" />
  <mx:Button label="Delete Duplicate" click="{DupImg.source = null}" />
</mx:ApplicationControlBar>

<mx:Script><![CDATA[

private var loader:Loader;

private function duplicateImg():void{
  var ba:ByteArray = Img.content.loaderInfo.bytes
  loader = new Loader();
  loader.loadBytes(ba);
  loader.contentLoaderInfo.addEventListener(Event.COMPLETE, bytesLoaded);
}

private function bytesLoaded(event:Event):void{
  DupImg.source = loader;
}

]]></mx:Script>

(Flashが表示されない場合はこちら→duplicate.swf)

Home > Tags > tips

Meta

Return to page top