Flex Builder 3が首筋に噛み付いた
年の瀬なんで泣ける小話でも。
******
Flex Builder 3では、Flex Builder 3で作った各プロジェクトをFlex Builder 3から削除する際に二つオプションが選べる。
- Flex Builderからプロジェクトの参照だけを削除し、ファイル自体はマシン内に残す(デフォルト)
- Flex Bulderからプロジェクトの参照を削除し、さらにファイル自体もマシンから削除する(ゴミ箱に移動させるわけではなく、マシンから抹消する)
使用者が指定しない限り、前者の削除方法が選ばれる。しかし、例えばプロジェクト名を中途半端に間違えて作ってしまい、「あ、やべ、ミスった。消そ」とか、同じ名前のプロジェクトを作り直したい場合なんかは後者を選ぶ方が楽な場合がある。僕自身も面倒が少ないからという理由で後者の削除方法を使うことが少なからずあるのだけど、この後者がやばい。後者のファイル削除の範囲はプロジェクトと関係あるかないかに関わらずそのプロジェクトのディレクトリ配下全部だからである。以下実例。
Aさん(僕じゃないよ)の場合
Aさん(僕じゃないよ)は、普段Flex Builder 3のデフォルトのドキュメントディレクトリを使ってプロジェクトを作成していた。Macの場合だと
/Users/USERNAME/Documents/Flex Builder 3/
普通にFlex Builder 3を使っているとプロジェクトは全てこの階層配下に作成されるようになっている。(デフォルトの場所を使用するにチェックが入っており、他の場所へのプロジェクト作成がロックされた状態)。しかしそのときは、どうしてもローカルサイトでテストする必要があり、localhostにプロジェクト(PROJECT_JP)を作成した。
/Users/Username/Sites/PROJECT_JP/src/ /Users/Username/Sites/PROJECT_JP/bin-debug/ /Users/Username/Sites/PROJECT_JP/bin-release/
かくしてPROJECT_JPは完成したが、PROJECT_JPをローカライズしたもの(PROJECT_EN)を作成する必要があった。同様にしてローカルサイトにプロジェクトを作成するが、普段デフォルトのFlex Builder 3ディレクトリしか使っていなかったため、思わぬミスを犯す。一階層上をプロジェクトディレクトリにしてしまったのだ(つまりSites)。PROJECT_ENの内容は以下のようになった(PROJECT_EN内にPROJECT_JPが混在した状態)。
Aさん(僕じゃないよ)が予定していたディレクトリ構造
/Users/Username/Sites/PROJECT_EN/src/ /Users/Username/Sites/PROJECT_EN/bin-debug/ /Users/Username/Sites/PROJECT_EN/bin-release/ /Users/Username/Sites/PROJECT_JP/src/ /Users/Username/Sites/PROJECT_JP/bin-debug/ /Users/Username/Sites/PROJECT_JP/bin-release/
実際に作ったディレクトリ構造
/Users/Username/Sites/src/ /Users/Username/Sites/bin-debug/ /Users/Username/Sites/bin-release/ /Users/Username/Sites/PROJECT_JP/src/ /Users/Username/Sites/PROJECT_JP/bin-debug/ /Users/Username/Sites/PROJECT_JP/bin-release/
Sitesをプロジェクトのトップディレクトリに設定しているにもかかわらず、Flex Builder 3上ではこのプロジェクトディレクトリは”PROJECT_EN”と表示される点がポイント。Flex Builder 3のデフォルトのドキュメントディレクトリ配下のプロジェクトでは、Flex Builder 3上のプロジェクトフォルダ名とマシン上のフォルダ名は必ず一致するが、デフォルトではない場所にプロジェクトを作成した場合必ずしも両者は一致しない。
すぐに作成場所のミスに気づいたAさん(僕じゃないよ)は、PROJECT_ENを削除して作り直そうとした。その際横着をして前述の「プロジェクトの参照を削除し、なおかつファイルをマシンから抹消する」方法をとった。つまり「Flex Builder 3上でPROJECT_ENと表示されているプロジェクトの参照を削除し、さらにそのプロジェクトファイルをマシンから抹消する」方法をとったのである。その結果プロジェクトはたしかにマシンから削除され、以下のような構造になった。Sites配下には何も残っていない。っておい。
/Users/Username/Sites/
PROJECT_ENは正しく削除されたが、PROJECT_EN配下に存在していたPROJECTも跡形もなく削除されたわけだ。幸いPROJECT_JPのバックアップは前日にとってあったが、一日分の作業が跡形も無く抹消されたわけである。さらにローカルサイトという特別な場所に作成したのが災いした。ローカルサイトには今回とは無関係なフォルダが多数あったのである。例えば
/Users/Username/Sites/phpMyAdmin/
など。これらも同様に跡形も無く消去された。
教訓
今後は以下を死んでも遵守する、とAさん(僕じゃないよ)は言っている。
- Flex Builder 3のプロジェクトは可能な限りデフォルトのドキュメントディレクトリを使う
- 不要なプロジェクトは参照だけを削除する。実際のファイル削除は面倒でも手動で行う
- バックアップは頻繁に行う。そのためにコミット回数が増えても気にしない
ちなみにマシンルートに作ったFlexプロジェクトの完全削除とかどうなるのだろう。マシン破壊?誰か試してみて。トラウマになりそうでできんわ。
WonderFlで複数のクラスを使いたい場合
Tags: ActionScript
WonderFlでコンパイルできるのは1ファイルのみ(importできるのは指定されているライブラリのみ)。別ファイル化されているクラスを使いたくても使えないので、1ファイルに無理矢理押し込めてやる必要がある。» Fork me!!
一般仕様
//main.as package { import flash.display.Sprite; import com.borealkiss.Model; public class main extends Sprite{ public function main(){ } } }
//Model.as package com.borealkiss{ public class Model{ public function Main(){ } } }
WonderFl仕様
//All in one file package { import flash.display.Sprite; public class main extends Sprite{ public function main(){ } } } //No access modifier!!(i.e., public) class Model{ public function Model(){ } }
追記 2008/12/22
Flexアプリケーションが動いてる!!
色確認用 | Wonderfl Build Flash Online
インターフェイスにクラスを継承させる
Tags: ActionScript
注意:IEventDispatcherなどすでにインターフェイスが用意されているものについてはもっとスマートな実装方法がある(最下部の追記参照)
***************
インターフェイスはクラスではないのでクラスは継承できない。インターフェイスに他クラスの機能を扱えるようにして、あたかもクラスを継承しているようにする方法。
イントロダクション
親をインターフェイスで定義しておいて、その子クラスを使う場合、プログラム上では直接子クラスへの参照を作るのではなく親インターフェイスへの参照で扱う方が「後々」都合がよい場合が多い。例えばIDoSomethingインターフェイスを継承したDoSomethingクラスを作る場合は以下のように記述してやる。
package { import flash.display.Sprite; //main public class main extends Sprite{ //Defined as Interface private var _doSomething:IDoSomething; public function main(){ //Creates a DoSomething class. _doSomething = new DoSomething(); _doSomething.do(); } } } package{ public interface IDoSomething{ function do():void; } } package{ public class DoSomething implements IDoSomething{ public function do():void{ //Something is done. } } }
さてDoSomethingクラスは”クラス”なので、その他のクラスを継承することができる。例としてEventDispatcherクラスを継承させる。
package{ import flash.events.EventDispatcher; public class DoSomething extends EventDispatcher implements IDoSomething{ public function do():void{ //Do something } } }
本題
これでDoSomethingクラスはイベントの送受信ができるようになった。ここでようやく本題(の問題)に突入。先ほどmainクラスではDoSomethingクラスを使う際、DoSomethingクラスそのものではなく親インターフェイス(IDoSomething)への参照を用いて使うことにしていた。IDoSomethingへの参照変数に参照されたDoSomethingクラスがイベントを送信したらどうなるか。IDoSomething.dispatchEvent()メソッドはインターフェイスには定義されていないのでコンパイルエラーになる。
package { import flash.display.Sprite; import flash.events.Event; //main public class main extends Sprite{ //Defined as Interface private var _doSomething:IDoSomething; public function main(){ _doSomething = new DoSomething(); //Compile error as no such method is defined in the Interface. _doSomething.dispatchEvent(new Event("doSomething")); } } } package{ public interface IDoSomething{ function do():void; } } package{ import flash.events.EventDispatcher; public class DoSomething extends EventDispatcher implements IDoSomething{ public function do():void{ //Do something } } }
解決策
DoSomethingクラスではたしかに実装されているメソッドなのに、IDoSomethingインターフェイスでは定義されていない。それにもかかわらずmainクラスではIDoSomethingインターフェイスとして扱いたい場合どうするか。「実装したいメソッドを扱えるクラスを戻り値とする」メソッドを新たにインターフェイスに定義してやればよい。上記のEventDispathcerクラスのメソッドを扱いたい場合は、インターフェイスを以下のように再定義してやる。
package{ import flash.events.EventDispatcher; public interface IDoSomething{ function do():void; //New!! function get eventDispatcher():EventDispatcher; } }
そして、実際のメソッド内容を子クラスに追加、戻り値を子クラス自身とする。子クラスはEventDispatherクラスを継承しているところがポイント。
package{ import flash.events.EventDispatcher; public class DoSomething extends EventDispatcher implements IDoSomething{ //New!! public function get eventDispatcher():EventDispatcher{ return this; } public function do():void{ //Do something } } }
mainクラスは以下の通り。IDoSomething.eventDispatcher()メソッド経由でEventDispathcer.dispatchEvent()メソッドにアクセス。無事コンパイルが通る。
package { import flash.display.Sprite; import flash.events.Event; //main public class main extends Sprite{ //Defined as Interface private var _doSomething:IDoSomething; public function main(){ _doSomething = new DoSomething(); //Event successfully dispatched!! _doSomething.eventDispacther.dispatchEvent(new Event("do")); } } }
応用
同じようにして、例えば子クラスにDisplayObjectContainerクラスを継承させて、DisplayObjectContainerクラスを戻り値とするメソッドを定義してやれば、インターフェイスからDisplayObjectContainer.addChild()などを使うことができる。
package { import flash.display.Sprite; //main public class main extends Sprite{ public function main(){ var example:IExample = new Example(); var testSprite:Sprite = new Sprite(); //The interface acts as Sprite!! example.displayObjectContainer.addChild(testSprite); } } } package{ import flash.display.DisplayObjectContainer; public interface IExample{ function doExample():void; function get displayObjectContainer():DisplayObjectContainer; } } package{ import flash.display.Sprite; import flash.display.DisplayObjectContainer; public class Example extends Sprite implements IExample{ public function doExample():void{ } public function get displayObjectContainer():DisplayObjectContainer{ return this; } } }
***********************
追記 2008/12/14
やべえ。インターフェイスにはIEventDispatcherインターフェイスを継承させて、子クラスにはEventDispatcherクラスを継承させるだけで無茶苦茶スマートな構造になった。mutaさん thanks!!
package { import flash.display.Sprite; import flash.events.Event; public class main extends Sprite{ public function main(){ var doSomething:IDoSomething = new DoSomething(); doSomething.addEventListener(Event.COMPLETE,trace); doSomething.dispatchEvent(new Event(Event.COMPLETE)); } } } package{ import flash.events.IEventDispatcher; public interface IDoSomething extends IEventDispatcher{ } } package{ import flash.events.EventDispatcher; public class DoSomething extends EventDispatcher implements IDoSomething{ } }
MVCオルタナティブ
Tags: DesignPatterns
今日William Sanders - ActionScript 3.0 Design Patternsを読み直してて気づいた。ずっとViewは見た目オンリーで仕事は何もせずにControllerにまかせっきりだと思ってたけど、自分の衣装は自分で着るらしい。
一般的なMVC
いわゆる本に載ってるやつで意外にViewが働く。triadと呼ぶにふさわしく仕事がバランスよく分担されている。
- ユーザーがViewとインタラクション
- ViewがControllerにユーザーインタラクションを通達
- Controllerがインタラクション内容にそってModelを更新
- Modelが自身の変更をViewに通達
- Viewが更新されたModelを使ってView自身を更新
MVCオルタナティブ
僕がMVCだとおもってたやつでViewはほとんど仕事をしない。自分としてはModelとViewに全く関連性がないのはなかなか良さそうに思うんだけどどうなんだろう。Controllerが仕事しすぎ?
- ユーザーがViewとインタラクション
- ViewがControllerにユーザーインタラクションを通達
- Controllerがインタラクション内容にそってModelを更新
- Modelが自身の変更をControllerに通達
- Controllerが更新されたModelを使ってViewを更新
[iPhone] iPhone SDK 3日目
Tags: Books, iPhone, Objective-C
iPhone関連の記事が三つ目という意味で3日目。まず手元にあるiPhoneアプリケーションに関する本(後述Erica Sadunの本)がどうにもこうにも読解不能だったのでStephen KochanのObjective-C本を読んだがこれが当たり。読み進めていく上で他の言語と比較していると出てきてしまう不可解な点への解答が必ずといっていいほど数ページ以内に言及されており安心して読み進められる。特にメモリ管理の章が秀逸で、ガベージコレクション標準装備の言語に慣れ親しんでいる人が読むと目から鱗が落ちるのではないだろうか。OOPの理解があればスムーズに読み進められると思う。C言語特有のポインタだったり構造体だったりについても一章割いて説明しているのでC言語初心者でもまあなんとか。オススメ。
Stephen Kochan - Programming in Objective-C
Objective-Cの仕組みを理解して、じゃあ手元のiPhoneの本(後述Erica Sadunの本)を読もうと思ったらやっぱり無理だった。なんか読めなさすぎてむかついてきたので、amazon.co.ukのカスタマーレビューではどんな評価なのかと思ったら「初端から超ディープなところに連れてかれるから気をつけろ」「この本を解読するのにまた別にCocoaの本が必要」「ビギナーはストレスばっかりたまる」等々、一貫してビギナーがいきなり読む本ではないとのこと。自分だけ読めないわけじゃなくてほっとした。
Erica Sadun - The iPhone Developer’s Cookbook
じゃあ他に何かよい本ないのかと思って探したらもう一冊あった。この本のレビューは先ほどのものと違って、全部ポジティブなものばかり。「Erica SadunのiPhoneの本(上記)にがっかりしてたけどこれは読み進めやすい」「Aaron Hillegass(後述)よりもさらに読みやすいかもしれない」等々。とにかくステップアップ感覚が好評価の様子でベタほめ。
Dave Mark - Beginning iPhone Development: Exploring the iPhone SDK
前述のAaron HillegassはCocoa本Aaron Hillegass - Cocoa Programming for Mac OS Xの著者。Stephen Kochan(上記Objective-Cの著者)がObjective-C本文中でeasy-to-readスタイルのCocoa推薦書としてAaron Hillegassの本を挙げていた。そりゃ買うでしょ。一応自分の中の購入決心への流れをまとめると、
- 僕はErica SadunのiPhoneの本が解読できなかった
- Erica SadunのiPhoneの本が解読できなかった人がDave MarkのiPhone本をレビューでベタほめしていた
- Dave MarkのiPhone本はAaron HillegassのCocoa本よりeasy-to-readスタイルだとレビューでベタほめされていた
- Stephen Kochanが上記Aaron HillegassのCocoa本を読みやすいと推薦していた
- 僕はStephen KochanのObjective-Cの本が読みやすかった
ちなみに円高なので(1GBP=130円ぐらい?去年の今頃は250円だった)送料含めてもamazon.co.ukやamazon.comから買う方が安いかもですよ。意外と発送早いし。

