2010年10月12日火曜日

iOS用メッセージングライブラリ:MessengerSystem

iOS用メッセージングライブラリ:MessengerSystem



概要

    クラス間親子関係メッセージング用ライブラリ。 フルObjective-C。

    オープンソース。

    iOSのObjective-CランタイムでサポートされているNSNotificationを利用し、

    MVC -MVC 間の接続度を可能な限り疎にする。

    


    このライブラリのインスタンスを持つオブジェクト同士を任意に接続し、

    メッセージを投げ合う事が出来る。


    また、オマケで、アプリケーション内での接続内容をリアルタイムに可視化する

    外部視覚化ビュー、

    通信ログを持つ



    目標A、タグ:バリュー型での入力を可能にする

        Dictionaryをつれ回す形式はそのままだが、

        値に対して、文字列型の値を付けられるようにする。


    目標B、親子関係の動的指定

        親子関係を、子供から親を指定する手法で

        設定できるようにする。

        複数の親は許容しない。

        複数の同名の子供が存在する事を許容する。

        

    目標C、メソッドの外部呼び出し

        メソッドのポインタを渡し、受け取り側から遠隔実行できるようにする


    目標D、可視化

        つながりを可視化する

        可視ビューを作り出し、各インスタンスの関係、つながりを表示できるようにする。

     

    目標E、ログ取り

        通信記録を取れる/見れるようにする。


    目標F、遅延実行、遠隔実行

        遅延実行をタグ設定で実行できるようにする。



DL
    GitHubにアップロードされている。
    http://github.com/ToruInoue/MessengerSystem


APIドキュメント
    doxygenにて作成、添付


使用法
    1.MessengerSystemのインスタンスを持つ
        初期化時、自身のクラスidと、
        メッセージが来たときに実行したい、NSNotificationを引数に持つメソッドと、
        このMessengerの固有名詞を設定します。

- (id) initWithBodyID:(id)body_id withSelector:(SEL)body_selector withName:(NSString * )name

        
        Ex:TEST_PARENT_NAME = (@"親設定のMessenger"), TEST_CHILD_NAME_0 = (@"子供その1")と定義しておいたとする。

MessengerSystem * child_0 = [[MessengerSystem allocinitWithBodyID:self withSelector:@selector(testChildMethod:) withName:TEST_CHILD_NAME_0];





    2.クラス間を跨ぐように、Messengerどうしに親子関係を設定する事が出来る
        inputParentメソッドで他のクラスのMessengerの固有名詞を入力すると、
        入力元のMessengerを子供、固有名詞を指定されたMessengerを親として、
        通信関係が構築されます。

        とあるクラスA
MessengerSystem * parent = [[MessengerSystem allocinitWithBodyID:self withSelector:@selector(testParentMethod:) withName:TEST_PARENT_NAME];

        とあるクラスB

MessengerSystem * child_0 = [[MessengerSystem allocinitWithBodyID:self withSelector:@selector(testChildMethod:) withName:TEST_CHILD_NAME_0];

[child_0 inputParent:TEST_PARENT_NAME];


    その時のMessengerの関連を表示するビュー
        (MessengerViewControllerのview要素をwindowにaddSubViewしたもの)
    MessengerViewController親子関係をグラフィックで見る事が出来る。

        
    3.親子間でメッセージを送る
        可変長引数のNSObjectを渡す事が出来る。ただしnilで締める必要が有る。忘れるとエラー。
        
        parent → child_0
[parent call:TEST_CHILD_NAME_0 withExec:@"テスト",

 nil];



        child_0 → parent
[child_0 callparent:@"テスト",

 nil];  

        


        メッセージの受け取りは、
        Messenger生成時に指定したメソッドで行う事ができる。

    parentインスタンスを持っているクラス
- (voidtestParentMethod:(NSNotification * )notification {

    NSMutableDictionary * dict = (NSMutableDictionary *)[notification userInfo];

    NSString * exec = [parent getExecAsString:dict];


    if ([exec isEqualToString:@"テスト"]) {

        //やりたい事

    }

}




    childインスタンスを持っているクラス
- (voidtestChiidMethod:(NSNotification * )notification {

    NSMutableDictionary * dict = (NSMutableDictionary *)[notification userInfo];

    NSString * exec = [child_0 getExecAsString:dict];


    if ([exec isEqualToString:@"テスト"]) {

        //やりたい事

    }

}


    kvsでの値受け渡しが可能。

[child_0 callParent:TEST_EXEC_3,

 [child_0 tag:@"タグ" val:],

 nil];

 


   

    4.ブロードキャスト/相手を確定して通信
        親→子へは、子供の名称でのブロードキャストが可能。
        同名の子供が何人いても、メッセージを送付できる。

        子供の子供、などのネストが可能。
        


    5.遅延実行、遠隔実行
        命令の遅延実行(floatで指定した秒数後に起動)、
        自分が持っているメソッドの遠隔実行
            (受取手側から引数を入力してのメソッド実行)
            などが可能。

             
        parent → child_0 遅延実行
            0.3秒後にメッセージを送る

[
parent call:TEST_CHILD_NAME_0 withExec:@"テスト",

 [parent withDelay:0.3],

 nil];




        child_0 → parent 遠隔実行

            child_0を保持しているクラスが持っている、下記
        - (void) sayHello:(NSString * )str;
            メソッドをparentを保持しているクラスで遠隔実行

[child_0 callParent:TEST_PARENT_INVOKE,

 [child_0 withRemoteFrom:self withSelector:@selector(sayHello:)],

 nil];



            受け取ったparent側で、引数だけを渡して実行!

- (voidtestParentMethod:(NSNotification * )notification {

    NSMutableDictionary * dict = (NSMutableDictionary *)[notification userInfo];

    NSString * exec = [parent getExecAsString:dict];


    if ([exec isEqualToString:TEST_PARENT_INVOKE]) {

        [parent remoteInvocation:dict, @"遠隔実行で親から子供の、子供から指定されたメソッドを実行しています。", nil];

    }

}

  



    4.親子関係の動的変更
            親から子をパージ、子から親をパージ、などすると、子から親を再指定できるようになる。
             動的に変更可能。
        [child_0 removeFromParent];

        [parent removeAllChild];



ライセンス
    未定。とりあえず数日だけ公開。
    BSDかGPL2。
    このライブラリを使用した事によるどのような損害、被害についても弊社はその責任を負わないものとする。


    







2010年10月9日土曜日

doxygenでObjective-CソースからDoc生成

doxygenでObjective-CソースからDoc生成


概要
    Objective-Cのソースに対して、JavaDoc形式コメントから
    HTMLなどでドキュメントを作成してくれるツール、
    doxygenについての導入メモ
    
    もちろんC++,Cにも使える。
    (というかObjective-C専用の設定は無かった。
        だがウマく出たので良しとする。)
    

目的
    Objective-Cプロジェクト中に、JavaDoc形式で書かれた文言から
    ドキュメンテーションを自動作成する。
    といっても、動作原理はJavaDocと変わらない。
    記法もJavaDocそのものなので、
    @paramとかの記述にも対応してくれる


インストール
    Mac向けのPackageで用意されているので、DLしてインストールする。
    Wizardに従う。

    doxygen
        http://www.stack.nl/~dimitri/doxygen/


使い方
    GUIがある。
    doxygenをインストールしたフォルダにappがあるので、起動。
    先ずは生成されるドキュメントのタイトルとかをセットする。

    Step1
    プロジェクトの置いてあるフォルダを指定。

    Step2については下記、
    Project name,versionは適宜。
    Source code directory 
        ソースが置いてある場所を指定。
        iPhone系であれば、classファイルのフォルダを指定するだけでOK。
        
    Specify the directory where doxygen should put ~
        doxygenがドキュメントを出力する場所について、指定する。
        Step1をこなせば、プロジェクトの置いてあるフォルダ近辺が自動入力される筈。
    次に、実行する。
    Runのタブを押し、Run doxygenボタンを押す。以上でドキュメント生成が完了する。
    Show HTML output を押すと、完成したドキュメントが表示される。
    内容をもっとJavaDocらしくきちんと書けば、return,paramなども表示される。
    なかなか使えるんじゃなかろうか。


その他
    Graphviz というクラス関連図描画ソフトと連携しているらしいのだが、
    どうも出力時にエラーが出るようで、まだ正確に使っていない。

    Graphviz
        http://www.graphviz.org/

2010年9月27日月曜日

GWT Designer

GWTDesigner について


概要
    GUIがある、Webページデザイン用のEclipseプラグインについてです。
    GWTでのGUIデザインを視覚的に行うことができ、さらに外部からインスタンス化する事が非常に簡単。
    GUIパーツを簡単に作り出す事ができます。
    



ライセンス登録
    サイトから行う。
    →Googleによる買収が完了。ツールが無償で提供されるようになりました!    やったね。 -toru inoue 10/09/XX 18:29 


使い勝手
    めっちゃいい。
    重量があるのがネックだが。
    詳細は今後書く。
    ・ひな形クラスで、ビュー(MVCのView)として使える要素が手軽に作れる。
    ・レイアウト手段として、入れ子の定義などがGUIで手軽に行える。
    ・ソースコードへの編集に対応しており、描画インスタンスの追加、変更、
        シングルトンなどの変化も即座に反映される。











2010年9月24日金曜日

iPad から VGA出力

iPadからVGA出力



概要
    iPadに専用VGA出力コネクタを繋いで、iPad上の画面を転送するプログラム
    参考はGemmelさんの下記記事。いつも大変参考にさせていただいています。
    http://mattgemmell.com/2010/06/01/ipad-vga-output
    Thanks a lot! Matt!


制作内容
    手順はかなり簡潔で、

0、インスタンスを用意する
    UIWindowexternalWindow;

    NSArrayscreenModes;

    UIScreenexternalScreen;


1、外部スクリーン数を取得し、1より多い=外部スクリーンがある、と見なす。
    if ([[UIScreen screens] count] > 1)

2、外部スクリーンをインスタンスとして取得し、所持する。
    externalScreen = [[[UIScreen screens] objectAtIndex:1] retain];

3、そのスクリーンが取り得るスクリーンモード、サイズ情報をNSArrayで取得する
    screenModes = [externalScreen.availableModes retain];//スクリーンモード

4、スクリーンモード配列から目的のモードをUIScreenModeとして取得し、
    外部スクリーンインスタンスにモードとしてセットする。

    UIScreenMode * desiredMode = [screenModes objectAtIndex:目的のモードが格納されているインデックス];

5、外部スクリーンモードインスタンスを自作の外部ウインドウインスタンスにセットする
    externalScreen.currentMode = desiredMode;

6、指定したUIScreenModeからサイズを読み出し、外部ウインドウインスタンスのサイズとしてセットする
    CGRect rect = CGRectZero;

    rect.size = desiredMode.size;

    externalWindow.frame = rect;


7、外部ウインドウインスタンスをiPadが使用するウインドウとしてセットする
    externalWindow.hidden = NO;

    [externalWindow makeKeyAndVisible];




2010年7月12日月曜日

NGを画像化する

NGを画像化する


概要
    知り合いのプロジェクトで、見た目にこうなったらNG、そのときのNGの種類を客観的に判断できるよう
    シート化してある物があった。

    →判断の他人化、他人がバグを見分ける際に、まとめておくと凄くいい! という例。

    モノがグラフィカルなだけに、こう見えたらこれだ! と言ってね。
    もしかして、、、をバグ発見に用意する、というアイデア。

    不測のバグに対して悪影響を生みそうだが、グラフィカルなバグに関して人の目で
    チェックをかける価値はやはり捨てられない。

    不測のバグであるか否か、を判断するためには、報告を受け直した際に、確認が必要。
    運良く(悪く?)直っていなければ、という、Luckが必要な手法だけれど。

    不測のバグなら、新たなバグコレクションとして例を足せばいい。
    
    
    そのバグが何に起因するのか、というのをプログラマなり問題解決者に伝える際、
    見た目にわかりやすい例は、現状でのまっとうな解の一つだと思う。

2010年6月14日月曜日

Mac用のタイムスタンプ入力ショートカット

 Mac用のタイムスタンプ入力ショートカット



概要
    Macで使用できる、タイムスタンプ入力のアプリケーションを探してみた。
    無償で使用できる下記を発見、ここに使い方をメモしておく。

    WordService 2.7

    コマンド+特定キーで、

    10/06/14 16:06:36

    日付と時刻が入力できる。

    どんなアプリケーションからでも、文字列としてショートカットで時刻を入力できる!
    これで書式統一が楽になる。



ダウンロード

    http://www.devon-technologies.com/download/index.html

    からDL

    Freeware Applications and Servicesの中にある。



インストール方法

    0.ダウンロードする。

        WordService.service ファイルを含んだフォルダ WordService が手に入るはず。


    1.HD > "ライブラリ" 下に、"Services" フォルダを作成する。

        (今までにインストールしたソフトによって、すでに有る場合もあるかも。)

        ダウンロードしてきたWordService.serviceを、上記フォルダに入れる。


    2.ログアウト&ログイン

        Serviceがログインに絡んで設定される機能のため、

        一度ログアウト(終了でもOK)する。

    

    3.テキストエディットを起動、

        テキストエディット > サービス > サービス環境設定 を開く

        先ほどインストールした内容が、一覧で表示される筈。


    4.特定のチェックボックスにチェックを入れる

        Long Date, 

        Long Date & Time, 


        Short Date, 

        Short Date & Time, 

        Time 

        以上のチェックボックスにチェックを入れる。(使いたい機能の物だけ選択してもいい。)



    5.再びテキストエディット

        テキストエディット > サービス を選ぶと、上記4で選んだ項目が表示されている筈。

        選択すると、文面に時刻が入る。


        

        ⌘+{ や、 ⌘+_ で使えるShort Date 系が便利。

        より詳細に編集、コマンド割当ができるのかな。

        →ぱっと見できませんでした。



入れてみて

    他にも、いろいろあるようで。探すと面白いかもしれない。

    関数計算、とか。


雑感、Objective-CとHTML5

雑感、Objective-CとHTML5 by -toru inoue 10/06/14 11:59 

概要
    Objective-CとHTML5は、言語と勧告なのだけれど、
    実際に実装される仕様についての言語的共通点が微妙に多い。    
    といってもピンと来る人ってあんまりいないだろうな、、
    両方やってる人間って何人いるんだろ。
    にてて個人的に非常に嬉しいとこ見つけたので書く。


動作環境がある
    ここでいう動作環境とは、自分の書いたプログラムが動作するのを見張っている監視者のようなもの。
    JavaのEnvironment、つまりVMみたいなもの。(正確にはVMの役割の一つ)

    Objective-Cは感覚的にはC言語で書いた物がC言語上で動くVMと一緒。もっと一般化してもらってもよろしくてよ。
    ,,流石に記法が変態的すぎるとの声を良く聞く。Lispかw 可読性は他の言語と一緒だと思うけどね。
    挙動は、サーバに非常に近い挙動をする。 
    到達順番が正確に維持されている手元にあるサーバ、という表現がいいんじゃなかろうか。

    
    
    そういえばObjective-Cって、C言語を書いてC言語で動かすVMだけれど、
    X言語を書いてX言語で動かす、っていうVMは
    世界に唯一のものなんじゃなかろうか。
    あ、C#があったっけ。 C#ってC言語内包してたっけな、、



メッセージングがある
    両者とも、メッセージングがある言語環境である。 
    HTML5の実装例をまだ一つも見てないが、用意されているAPIはとても素敵。

    メッセージングがあるから、宛先を決めずにメッセージを放送(指向性のない出力、ブロードキャスト)し、
    受け止めたい人がそれらを受ける、という事が出来る。

    最悪、
    受け手のプログラムさえ活性化していれば、(インスタンス化されていれば)
    メッセージの打ち手は受け手の事を知らなくてもいい。 = ポインタを保持していなくてもいい

    特にC言語系の場合、オブジェクトをインスタンス化するのに立ち会うか、
    インスタンスのポインタを知らなければアクセス出来ないもの、なのだけれど
    (ポインタ直指定でのインスタンス化とポインタ値所持は論外として)
    Objective-Cならば、動作環境があるので、それらはなんとかなる訳だ。

    たしかCのBoostあたりでも、そういったメモリ上にオブジェクトをプーリングする機構の
    果てにメッセージングがあったように思う。
    最後に見たのもう2年以上前だ、、、
    
    利点は既に述べた、「打ち手は受け手の事を知らなくてもいい」という事。
    機能をステートマシン化する事で、どんなオブジェクトとでも通信できる。
    
    メッセージングが或る言語は、自身の中を不特定の情報が飛び交う、ミニサーバ郡プログラムになれる。
    打ち手は、受け手が判定することで身元判定をし、
    受け手は次の受け手へと情報やコマンドを発信する。

    (HTML5で実装されようとしているMessage系のシステムと、
        WebWorker系のシステムは、スレッド絡みの話でもあるから、
        きっと組み付いてるんだろうなあ。)
 
    うううううーん、素敵。

2010年6月13日日曜日

Objective-Cでのメッセージングシステム

Objective-Cでのメッセージングシステム 


概要

    Objective-Cのメッセージングのシステムを使い、

    インスタンス間の通信を行うクラスを自作した。

    NSNotification を応用した、メッセージ伝達を行う。


    このクラスのインスタンスをもつオブジェクト同士は、

    お互いのポインタを全く知らない(保持しない)状態での交信が可能になる。


    一言で言うと、アプリ内疑似サーバ立ち上げ機能である。


    通信の順序は、タイマー実行を行わない限り、NSNotificationのシステムにより、

    通信完了まで確実に入力順が保たれる(メッセージの追い越しは発生しない)



    メッセージングする同士のIdentifyを確認するためのキーとして、

    Identifier(メッセージの送信者を特定するためのIDint値)を用意する必要がある。

    セントラル/レシーバーという役割分担を行う必要がある。


    セントラルからのメッセージングは、セントラル自身と指定したレシーバーへと伝達される。

    レシーバーからのメッセージは、セントラルへと伝達される。


    おまけで、下記実行を可能にしてある。

    ・遅延実行(別スレッドでの実行を可能にする)

    ・コマンドの入力(ヘッダクラス参照)

 


ダウンロード

    http://homepage.mac.com/sassembla/download/messagesystem/com.zip



設計思想

    このクラスに自発的に用意されている制限として、セントラルは一つ、レシーバーは一つあるいは

    複数存在する事が想定されている。

    各レシーバーからのメッセージは、必ずセントラルへ集約され、セントラルで状態によって各レシーバー

    (か、セントラル自身)へとメッセージを伝達、処理を進める事が可能。


    →このような区別が存在する理由は、下記2つ。

    ・完全にレシーバー間の通信を行う場合、メッセージ内容を把握する事が不可能になるため。

    ・メッセージの分別によってアプリケーションを複数のモジュールに分解し、

        分業を可能にするための、最低限の仕組み化のため。

 


使用例

    下記のように使用する。



1.初期化:


セントラル.h

//インスタンスを設定する

MessageSystem * messenger_default_reciever;


セントラル.m

//メッセージシステムインスタンスをセントラルとして初期化する。 

messenger_default_observer = [[MessageSystem alloc] initWithCentralObserver:self centralNamed:@"" recieverNamed:@""  withIdentifier:0 withVersion:20100610 withSelector:@selector(defaultCentral:)];



//メッセージを受信したとき行うメソッド、- (void) defaultCentral:(NSNotification * )notification を用意する

- (void) defaultCentral:(NSNotification * )notification {

    NSLog(@"defaultCentral");

    NSMutableArray * array = (NSMutableArray *)[notification userInfo];


    int sender = [[array objectAtIndex:MESSAGE_SENDER] intValue];

    NSLog(@"sender_%d", sender);


    int command = [[array objectAtIndex:MESSAGE_STATEMENT] intValue];

    NSLog(@"command_%d",command);

}




レシーバー.h

//インスタンスを設定する

MessageSystem * messenger_default_reciever;


レシーバー.m

//メッセージシステムインスタンスをレシーバーとして初期化する

messenger_default_reciever = [[MessageSystem alloc] initWithRecieverObserver:self centralNamed:@"" recieverNamed:@""  withIdentifier:1 withVersion:20100610 withSelector:@selector(defaultRecieve:)];


//メッセージを受信したとき行うメソッド、- (voiddefaultRecieve:(NSNotification * )notification を用意する

- (void) defaultRecieve:(NSNotification * )notification {

    NSLog(@"defaultRecieve");

    NSMutableArray * array = (NSMutableArray *)[notification userInfo];


    int sender = [[array objectAtIndex:MESSAGE_SENDER] intValue];

    NSLog(@"sender_%d", sender);


    int command = [[array objectAtIndex:MESSAGE_STATEMENT] intValue];

    NSLog(@"command_%d",command);

}



2.実行

ケースa.
    //セントラル.mのインスタンスにて、下記を実行すると、

    [messenger_default_observer sendMessage:100,nil];


    //セントラル.mのインスタンスにて、defaultCentralメソッドが発動する。
    defaultCentral~

    →セントラルからセントラルへのメッセージ送付にはsendMessageメソッドを使用する。 宛先指定は特にない


ケースb.
    //セントラル.mのインスタンスにて、下記を実行すると、

    [messenger_default_observer flushMessageTo:1 withNil:101,nil];


    //レシーバー.mのインスタンスにて、defaultRecieveメソッドが発動する。
    defaultRecieve~

    →セントラルからレシーバーへのメッセージ送付にはflushMessageToメソッドを使用する。 宛先指定は1の部分。


ケースc.
    //レシーバー.mのインスタンスにて、下記を実行すると、

    [messenger_default_reciever sendMessage:102,nil];


    //セントラル.mのインスタンスにて、defaultCentralメソッドが発動する。

    defaultCentral~

    →レシーバーからセントラルへのメッセージ送付にはflushMessageToメソッドを使用する。 宛先指定は特にない



    MessageSystemのインスタンス同士に、クラス間の関連や、ポインタの共有が一切無い、ということに注目。
    なのに通信内容がお互いのクラスに届いている。素敵すぎる。



そのほか
    ・NSオブジェクトを送る事が可能
    sendMessage,flushMessageToメソッドともに、可変長でNSObjectを格納、発送できるようにしている。
    [messenger_default_observer flushMessageTo:1 withNil:101, @"NSオブジェクトを継承したものなら、何でも送れる!", nil];
    NSNumberやNSDictionaryも送れる。


    ・今のところ、単一の識別子しか使えない
    セントラルとレシーバーは、このサンプルでは単一の組み合わせとして動いている。
    セントラル一つ、レシーバ数は無制限だが、この組(セントラル+レシーバーxN)としてしか使えず、
    ひとつこの組み合わせを作ったら、別のセントラル+レシーバーの組み合わせを使用する事が出来ない。
    可能にするには、独自の名前でセントラル+レシーバーの組を実装できるように、関係性アイデンティファイの機能が必要。
    →centralNamed:@""などがあるのは、その実装前の準備。


    ・Deallocが非常に難しい
    MessageSystemを持ったインスタンスをDeallocする際は、先にMessageSystemインスタンスをDeallocする必要がある。
    遅延実行と絡むと、分解が非常に難しくなる。
    また、MessageSystemを介した、MessageSystemインスタンスを持つオブジェクトのDeallocが可能。(なんて恐ろしい)


    ・ポインタを管理する必要が無いようにできたりできなかったり
    Object * a = [[Object alloc] initWithMessageSystem];//Objectクラスは初期化時にMessageSystemインスタンスを初期化
    と書くと、
    記述したブロックを抜けても、MessageSystemを介してaにアクセスする事が出来る。
    ぶっちゃけメモリリークだが、MessageSystemを介して管理が出来るのが強み。
    Deallocをマスターすれば、いろいろなオブジェクトを、MessageSystemを介したシングルトンとして
    意識せず実行する事が出来る。


今後の展望
    要望、バグがあれば、是非ブログまで連絡ください。
    
    そのうちGoogleCodeにアップしようかな。


フォロワー