MXMLとロジックを切り分ける

2009 年 7 月 2 日

切り分けは必要?

MXMLファイル内にScriptタグを置くことで、簡単にロジックを記述することができます。
ですが、ロジックが長く、複雑になるにつれ、管理がしにくくなっていきます。

僕個人は、MXMLはあくまで”見た目(ビュー)”の部分を構築するのみで、スクリプトは記述しないことをルールにしています。
ちょっとした処理ならMXMLファイルに直接書いてしまったほうが楽なこともありますが、長い目で見れば、分けたほうが構成が統一され、ソースの管理がしやすくなると考えています。

外部スクリプトファイルを利用

もっとも単純な方法は、スクリプトファイルを別に用意し、スクリプトタグのsource属性に指定することで読み込む方法でしょう。
これはスクリプトタグ内に記述するのと同じ意味になります。
スコープは元のMXMLファイル(ひとつのクラス)の中のコードとして扱われます。

ただ、この方法でちょっと気になるのは、外部に切り離したファイル単体では、クラスとして成立していないということ。もとのMXMLファイルがひとつのクラスとして扱われ、外部ファイルはその一部となります。
この「宙ぶらりん感」が気になるかならないかは人それぞれですが、僕は気になりますw

IMXMLObjectインターフェースを実装する

これは、外部に切り離したロジックをひとつのクラスとして実装し、それをMXMLファイル内にタグ(プロパティと言い換えても間違いでは無いでしょうか?)として埋め込む方法です。

たとえば、MXMLファイルのトップレベルタグ下に以下のように記述します。

<logic:TestLogic id="testLogic" />

最初の”logic”となっている部分は名前空間(パッケージ)です。
カレントディレクトリに”logic”というサブディレクトリがあると仮定すると、この名前空間の定義は以下のようになります。

xmlns:logic="logic.*"

この記述をMXMLファイルのトップレベルタグに入れておくことで、このスコープ内で”logic:xxx”と書いた場合は、logicディレクトリ下のxxxというクラス(おそらくxxx.asファイル。もしくはxxx.mxmlかも)を読みにいきます。

先の例では、TestLogic.asというファイルを用意してあります。
このファイルにはTestLogicクラスを記述し、IMXMLObjectインターフェースを実装します。

IMXMLObjectインターフェースで定義されているメソッドは(現時点では)1つだけ。
initialized()メソッドです。
Flexでは、コンポーネント初期化後にこのメソッドが呼ばれます。

定義は以下。

public initialized( document:Object, id:String ):void;

第一引数にはこのオブジェクトを作成したドキュメントオブジェクト(つまるところ親コンテナかな)、第二引数にはドキュメントからこのオブジェクトを識別するための識別子(そのまんまid)が渡されます。

親コンテナへの参照をメンバ変数に持っておくのが定石です。
以下、よく見る基本形ですね。

public function initialized(document:Object, id:String):void
{
// _viewはメンバ変数、XXXはMXMLドキュメントの型。
_view = document as XXX;
    
// 初期化完了時のイベントをハンドリングしておく。
// 各コンポーネントへのアクセスは初期化後におこないます。
_view.addEventListener( FlexEvent.CREATION_COMPLETE, onCreationCompleteHandler );
}

まどろっこしく感じますが、慣れると構成がはっきり分けれますし、結構重宝します。

さらに一歩進めてみる

前例では、ロジックを専用の別クラスとして切り分けました。
ただし、MXMLドキュメントクラスとロジックのクラスは別物です。

では、MXMLドキュメントクラス自体をひとつのスクリプトファイルで記述できないのでしょうか?

実は、できます(その効果のほどは定かではありませんが・・・)。

たとえば、mx:Applicationのかわりに自分でmx.core.Applicationクラスを継承した”MyApp”というクラスを定義します。
MXMLファイルはこんな感じ。

<?xml version="1.0" encoding="utf-8"?>
<my:MyApp xmlns:my="*" styleName="plain">
</my:MyApp>

MXMLファイルと同じディレクトリにMyApp.asを置いてコンパイル。
真っ白い、何も無い画面がでます。

場合によっては使えるかもしれませんし・・・。
なんでもスクリプトで書きたい方はいいかもしれません。

ただ、やってみるといろんな落とし穴が待っているのですが・・・。

あらら、指に水ぶくれが・・・

2009 年 6 月 22 日

なんちゃってギタリスト兼ベーシストな自分。たまに(特に休みの日なんか)集中的に弾いたりするんですが、特にベースを弾くと指に水ぶくれができちゃいます。

きちんと定期的に弾いてれば、指も硬くなるんでしょうけど、不定期で間けっこうあいたりして、急に一気に弾くから、こんなになっちゃうんでしょうね。

痛いっていうほどではないんですが、どうにも違和感が・・・。スライドとかすると、破れそうだし。

圧倒的に弾きこみが足らんのですね。
猛省・・・。

Flashプレーヤーの旧バージョン取得

2009 年 6 月 19 日

バージョンxxで動かないんですが・・・

Flashプレーヤーのバージョンも、この記事を書いている時点ですでに2桁に突入して久しい。
その間(もちろんこれからも)多くの変更と修正を経て、Flashプレーヤーは進化していますが、次第に過去のバージョンとの互換性も損なわれているのが現実。

Flashプレーヤーのアップデート率は高(いらし?)く、リリースから数ヶ月もたてば、ほとんどのユーザが最新版となっている(ようだw)。

ただ、意識的にアップデートしないあまのじゃくや、アップデートの仕方がわからない、アップデート自体がわからない、Vistaのセキュリティー問題などでアップデートが困難になってしまった、などなど旧バージョンをそのまま使っている人もいる。

で、Flashがうまく動きませんとクライアントにいわれた場合、最新版のプレーヤーを入れれば動きますよと単純に言い切れない現実もあるわけです。

旧バージョンでテストしたい

今回、私の身にもそんな事態が。

1つ古いバージョンで動作不備が発生したが、プレーヤーのアップデートを促すのではなく、そのバージョンでも動くようにとの依頼。
もちろん、実装・テストのためにプレーヤーのダウングレードが必須。

では、過去のバージョンを手に入れよう。

関連リンクのページでAdobeがテスト用のプレーヤーを提供してくれています。

もちろん、保証とかは一切無しです(当然ですが)。
セキュリティーアップデートや、バグの修正がない「素」の状態の当時のプレーヤーだと思いますので、なにか起こっても全て自己責任にてカバーしてください。

関連リンク

Adobe テスト用のアーカイブ版提供ページ

三沢さん・・・

2009 年 6 月 14 日

プロレスリングノアの三沢選手が6月13日、広島での試合中にバックドロップを受け、頭部を強打。意識不明となり、そのまま帰らぬ人となった。

まさかの出来事。

いまだに頭の中が整理できていない。

もっとも好きなレスラーでした。プロレスラーとしてというよりも、人として尊敬していました。
理想と信念の元、自らの団体を立ち上げ、常に自ら先頭に立ち、言葉よりも行動で示し、それでいて気さくで人間臭く、飾らない・・・。
その生き様に憧れていました・・・。

プロレスラーがどれだけ身を削り、命懸けでリングに上がっているのか改めて痛感させられました。

世の中には、プロレスを否定するような人がたくさんいますが、そんな人たちに言いたい。

信念を持っていますか?
命懸けで闘っていますか?
全力を尽くしていますか?

リングの上は、常に危険と隣り合わせです。
いつかこんな日が来るのではないかと、そんな不安も心のどこかにはありましたが、まさか現実になってしまうとは・・・。

残されたご家族、選手、関係者の心中を思うと、やり切れません。

今はただ、本当にお疲れ様でしたと。
そして、たくさんの夢を与えてくれて、ありがとうございましたと。

三沢さんのご冥福を心よりお祈りいたします。

クモが・・・

2009 年 6 月 8 日

部屋の窓の外に、けっこうでかいクモが巣を作った。

デスクが窓に向いているから、いやでも目が合ってしまう。

おまけに、窓を開けると巣に直撃。
虫系全般が苦手な自分はちょっと参ってます。

クモってどれくらいで引越しするのでしょうか・・・。

ViewStackの切り替えと初期化

2009 年 6 月 5 日

スタック切り替え時の初回処理で…

コンテンツを手軽に切り替えられるViewStack。しかし、思わぬ落とし穴も…。

スタックを切り替えたタイミングで処理をおこなったら、初回の切り替え時にのみ、エラーが発生。2回目以降は問題なく処理されるため、これはと思い調べてみると、コンテナの子がはじめて表示されるまで初期化処理が遅延されているそうです。

これは、初回の描画を高速化させるためだそうで、確かに(非表示のものも含む)大量のコンテンツを起動時に初期化していたら、開始までしばらくまたされることになります。

ただ、やはり意図的に非表示の子の初期化をおこないたいことがあります。
そんな時に利用するのがcreationPolicyプロパティです。

creationPolicyプロパティ

このプロパティ自体は、Containerクラスで定義されています。
手短に言うと、「コンテナ内の子をいつどうやって初期化するの?」っていうプロパティ。

“auto”、”all”、”none”、 “queued”のうちいずれかを指定できます。

auto
必要になった際に初期化。これが起動時最速。
ただし、ViewStack等では初回切り替え時に遅延が発生。

all
選択状態に関わらず、すべての子および子孫を初期化。
今回はMXMLでこれを指定することで解決しました。

queued
参考URLをみてください(汗)

none
子および子孫の初期化をおこなわない。
意図的に初期化を呼び出してやる(createComponentsFromDescriptors())必要があります。

参考URL

Containerクラス(creationPolicy)

PerlでWindowsのファイル属性を変更

2009 年 5 月 25 日

読取専用属性をなんとかしたい!

大量にあるファイルを書き換えるとか、巨大なファイルから目的の行のみ抜き出すとか、そういった処理をおこなうなら、Perlは非常に優秀です。
極めてシンプルなコードで結構な処理をやってくれるため、手作業でやるには到底無理なこれらの処理をするために、小さなプログラムを書くことがよくあります。

今回、わけあってTortoiseのentriesファイルを書き換える必要に迫られたので、Perlで一括処理してやろうと目論見ました。
が、このファイル、なんと読取専用属性が指定されてるじゃないですか。
広大な作業コピーの中の.svnディレクトリをせっせと開いて属性を変更してたら、日が暮れてしまいます。
なんとか一気に属性を変更するすべはないものか…。

Win32::Fileを利用

ちゃんとありました。Win32::Fileモジュールに用意された、SetAttributesメソッドを利用すれば、Windowsのファイル属性を変更できます。

使用方法はいたって単純

use Win32::File;

Win32::File::SetAttributes( "ファイル名", "属性" );

属性には、以下が指定できます。

ARCHIVE
COMPRESSED
DIRECTORY
HIDDEN
NORMAL
OFFLINE
READONLY
SYSTEM
TEMPORARY

読取専用ということは、”READONLY”になってるわけですね。
これを取り除くには、”NORMAL”(標準)を指定してやればOK。

Win32::File::SetAttributes( $filename, NORMAL );

無事、ファイルの属性が変更されました。
もちろん、READONLYを指定しなおせば、また読取専用に戻ります。

SetEnvディレクティブで環境整備

2009 年 5 月 22 日

設定ファイルの読み替え

開発環境と本番環境で、ソースを読み替えたいことが良くあります。特に設定ファイルなどはその典型で、環境に依存する各種情報を本番と一致させることは困難(ホスト名や、パス、DBへの接続情報など)。
そこで、環境ごとの設定ファイルを用意して読み替えることになりますが、どうやって読み替えるかが問題。

まず、論外なのはそれぞれのスクリプトファイルに、設定ファイルへのパスをハードコーディングし、それを環境にあわせて都度書き換えるという手法。
当然、リリースの際にはパスを書き換えなければいけません。
これは明らかに余分な作業ですし、余分な作業が増えるほど、ミスの可能性も増え、また問題発生時の原因解明も難しくなります。

SetEnvを利用して、設定ファイルのパスを保持してみる

ApacheのSetEnvディレクティブを利用すると、環境変数を設定できます。このディレクティブは各種設定ファイルのほか、.htaccessファイルで記述もできます。

たとえば…

SetEnv DEFINE_FILE_NAME /path/to/define_file

のようにして、スクリプトから使用します。
PHPなら

include_once( $_SERVER['DEFINE_FILE_NAME']);

Perlなら

require $ENV{'DEFINE_FILE_NAME'};

のような感じで使います。

ただし、この場合は前提条件として、環境変数”DEFINE_FILE_NAME”が設定されていることが必要です。これがないと、そもそも動きません。
なければデフォルトの動作を用意しておくのが親切です。

SetEnvを利用し、パス以外の何かを保持

個人的に好んで使用しているのがこの方法です。

SetEnv DEV_FLAG 1

上記の場合は、環境変数DEV_FLAGを開発環境用のフラグとして利用しています。
この値が真として判定されれば開発環境、偽(0や未定義)なら開発環境以外のどこかです。
あとは、どう使ってもいいです。もちろん、設定ファイルの読み替えにも使います。
その他、各種メッセージの出力有無や、ログ書き出しの有無とか…このへんは設定ファイルに定義するかw

環境が、開発環境と本番とだけであれば、この方法がシンプルで汎用性があるのではないでしょうか。なにより、環境変数が未定義でもまったく気にする必要がないので、余計な不安要素がひとつ減ります。

XMLデータの埋め込み

2009 年 5 月 22 日

失敗例

Flexで設定ファイル的なものをXMLで用意し、コンパイル時に埋め込もうとしました。

書いたコードはだいたい以下のような感じ。

[Embed(source="setting.xml")]
public var SettingData:Class;

...

// こんな感じで使おうとする。
var settingData:XML = new SettingData();

なにやら、エラーがたくさん出たぞ?!

色々調べてみると、FlexのコンパイラがXMLの埋め込みに対応していないらしい。つまり、XMLとして変換(トランスコード)をおこなってくれないのだ。

対策

以前の記事で、ちょっと触れてますが、トランスコードに頼らずにデータをそのまま読み込んでおいて、自力でXMLとして初期化してやればいける。

[Embed(source="setting.xml",
mimeType="application/octet-stream")]
public var SettingData:Class;

...

// 以下のように使用
var settingData:XML = new XML( new SettingData() );

埋め込みの際のmimeTypeに”application/octet-stream”をしていすると、トランスコードをスキップして、生データが埋め込まれます。
こいつをXMLのコンストラクタに渡してパースさせればOK。

なんかちょっとまどろっこしいが、使えるからいいか。

可変長パラメータを扱う

2009 年 5 月 15 日

AS3から、関数に可変長のパラメータを渡せるようになりました。

function functionName(parameter0, parameter1, ...rest){
	...
}

restにはパラメータ配列が保持されます。別にrestである必要は無く、予約語以外の任意の名前をつけれます。

型にうるさい人にとっては気持ち悪いかもしれませんが、Perl出身の自分にとっては、まぁ、ありかなと。
引数の数や型によって挙動を変える、オーバーロード的な処理が、どうしても欲しくてしょうがないときに使えるかな、と。
あるいは、ArrayやVectorのpushのような関数(pushの引数は任意)を実装したい場合など。

ただ、パラメータの型チェックがだらしなくなるのは否めないので、使うには注意が必要ですな。