[iP]Objective-Cの文法メモ(ActionScript3.0との比較的な):インスタンスの作り方

クラスのインスタンスの生成方法
AS3はこんな感じ


//AS3
//newでコンストラクタを実行。
var hoge:MovieClip= new MovieClip();

obj-cはnewでなくて、各クラスによって色んな初期化メソッドが用意されているみたい。


//Objective-C
//NSStringの場合

//直接文字列を入れて初期化
NSString* str = @"HOGEHOGEO";
//NSString専用の初期化用のメソッドを使う
//文字列から生成
NSString* str = [NSString stringWithString: @"HOGEHOGEO"];
//既存の数値を利用して生成
NSString* str = [NSString stringWithFormat: @"ほげ:%d",100];

※またどのクラスでも通用する汎用の初期化メソッドもある。
(これがASのnewに近いのかな)
[[クラス名 alloc] init]
allocでメモリを確保して、initメソッドを実行
(initメソッドはNSObjectのメソッド)
あとallocでメモリ領域を確保した場合は使用後は自分で破棄しないとダメ
(iPhoneはGC無いので)
破棄は
[インスタンス名 release];


//Objective-C
//allocでインスタンス用のメモリを確保し、initを実行
NSString*  str = [[NSString alloc] init];
//※ただしNSStringのインスタンスは文字列の上書きができないので上記でインスタンスを作ると中身が空っぽのインスタンスができるだけとなる。
NSLog(@"%@",str);//出力:(ブランク)
//破棄
[str release];

2010/05/21:追記
objective-cでもnewを使ったインスタンスの生成はできる


//newを使った例
NSDate* date = [NSDate new];
//newを使わない(上と同じ意味)
NSDate* date = [[NSDate alloc] init];

[iPhone]Objective-Cの勉強メモ:デリゲートについて

アプリケーション自身とか、オブジェクト(クラス)が最初から持っている固有の動作(イベント的なメソッド?)がある。
たとえば、
アプリ起動時に実行されるメソッド、とか
アプリ起動中に着信があった場合に実行されるメソッド、とか
アプリ終了時に実行されるメソッド、など。

これらのメソッドは誰が実行するかを決めた上で、メソッドの中身を実装する必要がある。
誰が(どのクラスが?)、を決める作業をデリゲートを登録するという。
登録はIBのInspectorウィンドウから行う。
(IB使わなくてもObj-Cからも可能)
デリゲートとして登録されたクラスにそれぞれのメソッドを実装することで機能として使えるようになる。

感覚的には各クラスに用意されているメソッドをオーバーライドしているのと同じだろうけど、サブクラスを作る必要がなく、関連の無いクラスからでも、(オーバーライドしたようなメソッドとして)実行することができる。
IBで配置したオブジェクトについていちいちサブクラス作るのメンドイからこの仕組みがあるのかも。

[iPhone]Objective-Cの勉強メモ(ActionScriptとの比較的な):デバッグ出力はNSLog

Objecttive-CにおけるASでいうところのtraceにあたるものは、NSLog()
c言語ベースなのでprintf()でもコンソールに出力できるけどWarningがでたりするのでNSLog使った方がいいみたい。
(Object型のデータの出力に特化って感じかな?)

書き方は、printfとかと同様に変換指定子を使う。%+記号


//%@でオブジェクト型のデータ
NSLog(@"結果は:%@",@"あいうえお");//出力:結果は:あいうえお

[AS]progression PRMLLoaderクラスで、Error #1065: 変数 IndexScene は定義されていません。が出たときの対処法

PRMLLoaderクラスは、xml形式のデータを外部読み込みすることで、progressionのシーン構成を生成するクラスでちょっとはまったのでメモ。
PRMLLoaderクラスの使い方は、ProgressionによるFlashコンテンツ開発ガイドのp268に分かりやすく書いてあるのでその通りにならって実行したつもりが、題記エラーが表示されました。。。
だがしかし、書籍のサンプルファイルをダウンロードしてみるとちゃんとできてる。

書籍サンプルファイルと自分のプロジェクトの差異はなんなんだ?
とひと晩結果が、xmlでのクラスファイル(cls属性)の指定が間違っていました。

まずは、OK
(問題なしの書籍のサンプルは以下の画像のようなプロジェクト構成)

そして、NG
(題記エラーが表示されたプロジェクト構成)

※xmlはいずれも以下の通りとした


<?xml version="1.0" encoding="UTF-8" ?>
<prml version="2.0.0" type="text/prml">
	<scene name="index" cls="IndexScene">
	</scene>
</prml>

まずOKのNGの違いは、IndexSceneがパッケージでくるまれてるかくるまれていないか、ということ。
OKは、srcの直下にIndexScenen.asがあるのでパッケージにはくるまれていない。
NGは、srcの直下にあるcsr393pv3dというパッケージでくるまれている。

結論としては、パッケージからのパスをxmlのcls属性に設定することが必要。
srcの直下にあるcsr393pv3dにIndexSceneが含まれた場合は、、


<?xml version="1.0" encoding="UTF-8" ?>
<prml version="2.0.0" type="text/prml">
	<scene name="index" cls="csr393pv3d.IndexScene">
	</scene>
</prml>

これで正常に実行される。

つまり、srcからみたパスの構成を、xmlのcls記述に記述する必要がある。

[AS]エラーprogression「Error #1065: 変数 ContextMenuClipboardItems は定義されていません。」の原因

Progrssionの勉強中にはまったことメモ。
FlashDevelop(以下FD)のProgression用プロジェクトテンプレートを使って試してます。
(FlashIDE無しでも作れちゃうのはホント便利)

Progressionは基本preloader.swf、index.swfの二つを使うので、上記テンプレートの使い方として、FDのprojectファイルを切り替えてパブリッシュしていきます。

いろいろごちゃごちゃやってたときにpreloader.swfをパブリッシュ時に以下のエラーが発生

Error #1065: 変数 ContextMenuClipboardItems は定義されていません。

preloader,indexともにソースコードをデフォルトに戻しても直らないのでなんだこりゃ?としばらく途方にくれました。。。

で、原因はというと、preloaderの対象となるFlashPlayerのヴァージョンを9でパブリッシュして、indexではヴァージョンを10でパブリッシュしていたというオチ。
(そういや、ごちゃごちゃやってるときにプレイヤーは10じゃないとダメだということで、indexだけ変更してたんだったな、と)
ContextMenuClipboardItems はFlashPlayer10から使える機能なので、FlashPlayer9のpreloader.swfからFlashPlayer10のindex.swfを読み込んだ際に使えないよってエラーだったようだ。
エラー内容読めばそのまんまなんだけどね。

というわけで、FlashPlayerのヴァージョンを変更する場合は、preloaderとindexをそろえてやることを忘れずに。。。
(調べてないけどprogressionに限らず親が9で、10の子swfを読み込んだ場合は必ず発生するのかな?)
ちなみにFDでは各プロジェクトのプロパティからプレイヤ-のバージョンを変更可能。

[iPhone]C ポインタについて

すぐにこんがらがるのでメモ
ポインタとは、(変数の)メモリ上のアドレスの番地を格納するための仕組み


//ポインタの定義
//型名 *変数名
int *p;
int* p;//*の位置はこの書き方でもよい

int a=100;
//変数aのメモリ上のアドレスは、&aとなる。
//ポインタpにaを参照させるには、
p = &amp;a;//*pではないことに注意
//ポインタからaの値を取得するには
int b=*p;
printf(b);//出力:100

*の使い方についての注意
定義するときの*と、それ以外の*では意味合いが異なるらしい


//整数定義
int a = 100;
//整数型のポイントを定義
int *p;
*p = a;//これはNG
//定義後のポインタ変数に参照させるには、p = &a;
//ただしポインタ定義時の初期化でaを代入するのはOK
int *q = a;//これはOK
//定義するときの*と、それ以外の*では意味合いが違うということらしい

配列のときは配列名には、&はつける必要がない
ポインタ名は配列と同じようだ。


int a[20] = {1,12,23,34,45};
int b = 100;
int *pa;
int *pb;
pa = a;//&aにはならない
pb = &b;

//配列aの2番目の値を取得するには
//配列aを使う場合
printf("%d\n",a[1]);//出力:12
//ポインタpaを使う場合
printf("%d\n",*(pa+1));//出力:12
printf("%d\n",pa[1]);//出力:12

メモリを確保したポインタも配列と同じように扱える


int *bufa;
//100バイト分のメモリを確保
bufa = (int *)malloc(sizeof(int)*100);
bufa[10] = 123;
//配列のように参照
printf("%d\n",bufa[10]);//出力:123
//ポインタとして参照
printf("%d\n",*(bufa+10));//出力:123

[AS]as3でのスクリプトの実行の順番をmemo

swfを開いたときに実行される順番がこんがらがることが多いので調べた。

まずはドキュメントクラスのコンストラクタとメインのタイムラインのフレームアクションの比較

  • 1.ドキュメントクラスのコンストラクタ。
  • 2.メインタイムラインのフレームアクション

これは想像通り。

注意が必要なのはリンケージしたMCをnewするとき、(ドキュメントクラスの)コンストラクタでnewするか、(メインのタイムラインの)フレームアクションでnewするかというとき。
※前提として、メインのタイムラインにはMc(Mc0_tl)が配置してあり、Mc0_tlには、さらにMc(Mc1_tl)が入れ子で配置してることとする。

まず、ドキュメントクラスのコンストラクタでnewする場合

  • 1.DocumentClass コンストラクタ開始
  • 2.DocumentClass ムービークリップを動的に生成(new MyMc0_as())
  • 3.▲MyMc0_as コンストラクタ開始
  • 4.▲MyMc0_as コンストラクタ終了
  • 5.DocumentClass ムービークリップを動的に生成終了
  • 6.DocumentClass コンストラクタ終了
  • 7.★MyMc0_as フレームアクション開始
  • 8.★MyMc0_as フレームアクション終了
  • 9.mainTimeLine フレームアクション開始
  • 10.mainTimeLine フレームアクション終了
  • 11.MainTimeLineに配置した Mc0_tl フレームアクション開始
  • 12.MainTimeLineに配置した Mc0_tl フレームアクション終了
  • 13.Mc0_tlに配置した Mc1_tl フレームアクション開始
  • 14.Mc0_tlに配置した Mc1_tl フレームアクション終了

動的にnewしたMyMc0_asのフレームアクションが開始されるのは、ドキュメントクラスのコンストラクタ終了直後。
(メインタイムラインのフレームアクションの前)

次にメインタイムラインのフレームアクションでnewする場合(1フレーム目に記載)

  • 1.mainTimeLine フレームアクション開始
  • 2.mainTimeLine ムービークリップを動的に生成(new MyMc0_as)
  • 3.▲MyMc0_as コンストラクタ開始
  • 4.▲MyMc0_as コンストラクタ終了
  • 5.mainTimeLine ムービークリップを動的に生成終了(new MyMc0_as)
  • 6.mainTimeLine フレームアクション終了
  • 7.MainTimeLineに配置した Mc0_tl フレームアクション開始
  • 8.MainTimeLineに配置した Mc0_tl フレームアクション終了
  • 9.Mc0_tlに配置した Mc1_tl フレームアクション開始
  • 10.Mc0_tlに配置した Mc1_tl フレームアクション終了
  • 11.★MyMc0_as フレームアクション開始
  • 12.★MyMc0_as フレームアクション終了

動的にnewしたMyMc0_asのフレームアクションが開始されるのは、ステージに配置してあるMc0_tlのフレームアクションが全て完了してから。

ここで気をつけるのは、MyMc0_asのフレームアクションにたとえば、


//MyMc0_asのフレームアクション開始
var myProp:Number;
myProp = Math.random();
MyMc0_asのフレームアクション終了

と書いて、
メインのタイムラインのフレームアクションで、以下のようにすると


var mc:MovieClip = new MyMc0_as();
trace(mc.myProp);//出力:NaN(Math.random()の代入は実行されていない)

期待通りの結果が得られない。

乱数が代入された結果を得るには、メインタイムラインの2フレーム目以降で、mc.myPropを参照すればOK。

一応検証したファイルをアップします。
1004231414_asflowtest.zip
読んでもさっぱり意味がわからない人はどーぞ。。。

[AS]progression4RC departedSceneIdやdestinedSceneIdをif文とかで判定できないってときはここに注意

progressionを使ううえでの便利プロパティ。
departedSceneId
destinedSceneId
以前のエントリでも書いてるように、出発シーンと、到着シーンを取得できます。
ただし↑はprogression3の書き方。
progression4では、progressionインスタンスは無くなり、managerが持ってるプロパティ。


manager.destinedSceneId;
manager.departedSceneId;

これを使って、if文の処理をしたいときちょっとはまったのでメモ。
destinedSceneIdとかdepartedSceneIdをtraceすると、
/indexとか、/index/aboutとか、sceneIdを出力してくれます。
なので、戻り値のデータ型はString?と思いきや、実は違います。


trace(manager.departedSceneId)//出力(例):/index
trace(typeof manager.departedSceneId)//出力:object(stringではない)

なので、if文で判定するときは、↓だと上手く判定されません


//manager.departedSceneId == manager.destinedSceneIdは中身がなんであろうと常にtrueとなる
if(manager.departedSceneId == manager.destinedSceneId){
    //処理
}

traceしたときに見えるSceneId名で判定させる場合は.toString()をつければOK


//
if(manager.departedSceneId.toString() == manager.destinedSceneId.toString()){
    //処理
}

※2010/04/17/16:30追記
コメントにてequals()メソッドというものを教えて頂きました。
こっちの方が簡単ですね。


if(manager.departedSceneId.equals(manager.destinedSceneId)){
	//処理
}

※4のBetaまではtoStringなしでも判定してくれてたような気がするけど、RCからは無いとダメみたい。

[iPhone]Objective-Cの勉強メモ(ActionScriptとの比較的な):アウトレット・アクション

obj-c、1ヶ月くらい触らなかったら知識がほとんどすっとんでる。。。
最初はある程度まとめてどかっとやらないとマズイね。。。

以前とダブルこともあるだろうけどメモしていく。

◆アウトレット
:Viewに置いてあるオブジェクトの名前。
(ASでいうとインスタンス名みたいなもの)
スクリプトファイル(○○.h)でアクションを定義して、InterfaceBuilder(IB)で紐づける。
(スクリプト内で任意のオブジェクトを操作したいときのみアウトレットを定義)

◆アクション
:Viewにおいてあるオブジェクトに起因するイベントハンドラメソッド的なもの。
(AS3でいうとリスナー関数みたいなもの)
これもIBを使ってView上のオブジェクトと紐づける(addEventLisner()的な感じ)

※ASと違うところは、アウトレットは定義しなくても、アクションだけでも使える。
(オブジェクトとアクションの紐付けはIBでできるので)
(ASはインスタンス名をつけないとaddEventListener()使えないよね)
またアクションは引数でオブジェクトを取得可能:(id) sender
(AS3での、e.target的な)
アクションの対象オブジェクトだけをスクリプトで操作(透明にするとか)するなら、アウトレットなしで、アクションだけでOK
でも、アクションの対象外オブジェクトもスクリプトで操作する場合は、アウトレットの定義が必要。

[AS]FlashBuilderでのパブリッシュでエラーを修正しても再パブリッシュでエラーが消えない

FlashBuilder4の体験版で操作感を試してたときのハマッたこと。
(もともとFlexBuilderを使ってる人からしたらあたり前のことなんだろうけど)

ボクみたくFlashIDEとFlashDevelopしか使ってなかった人で、エディターとしてFlashBuilder使おうと思ってる人がひっかりそうなのでメモ。

状況:
ActionScriptプロジェクトを作成。
ドキュメントクラスでBetweenAS3の動作テストしようと思ったら、nullエラー発生。
ASを修正して再度デバッグモードでパブリッシュ(F11)するも同じエラーが表示される。
該当箇所全部消しても、同じエラー。ムキーなんじゃこりゃー。となる。

解決:
Flashデバッグのパースペクティブのデバッグタブに状況が表示されるのだけど
エラーのときにここが赤字で中断になるときがあってこのまま放置すると同じエラーが吐かれ続けるみたい。
※メインスレッド(中断:~ ってところ

デバッグタブ右の赤い■ボタンを押して終了するか、一式をデリートで消してから(ここではTest[WEBアプリケーション]を選択してDELETEキー)、改めてコード修正して再パブリッシュすればOKのようす。
再パブリッシュするときは、エラーを中断状態のまま放置しないで終了状態にしとけってことなのね。

そういやeclipse使ってのJavaのWEBアプリケーションの実行も処理を一度終了させてから実行しないとダメだったな。。。
せっかくの知識があんまり役立ってねぇ。。