MOSA Multi-OS Software Artists

MOSAはソフトウェア開発者を支援します

プログラマーに興味がある方なら誰でも入会いただけます。
MOSA Multi-OS Software Artists
===SINCE 1995===

  • iPhone/iPod touch アプリ紹介
  • MOSA掲示板
  • 活動履歴
  • About MOSA(English)

MOSADenバックナンバー 2004年8月発行分

  • MOSA Developer News[MOSADeN=モサ伝]第126号

    2004-08-31

    目次

    • SqueakではじめるSmalltalk入門   第8回  鷲見正人
    • 小池邦人の「Carbon API 徒然草」
    • 「Behind the WebObjects」    第26回  田畑 英和
    • ニュース・解説

    SqueakではじめるSmalltalk入門   第8回  鷲見正人

     本連載では、名前はよく耳にしていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。今回は、簡易ペイントスクリプトに、描いた絵を保存する機能拡張を施します。

    "01" | pen |
    "02" pen _ Pen new.
    "03" pen defaultNib: 3.
    "04" pen color: Color red.
    "05" [Sensor shiftPressed] whileFalse: [
    "06"    | position |
    "07"    position _ Sensor peekPosition.
    "08"    Sensor redButtonPressed
    "09"       ifTrue: [pen goto: position]
    "10"       ifFalse: [pen place: position]]

     このスクリプトは5行目でshiftキーが押されていることを関知すると、ループをやめて終了します。描いた絵を保存するためには、この後に任意の矩形領域を切り取り、それを画像ファイルとして保存するコードを追加すればよさそうです。手始めに、画面の矩形領域を基本図形GUIウィジェトである「モーフ」として取り出すコードを書いて、その動作を確認してみましょう。

    Form fromUser asMorph openInHand

     このメッセージ式をdo it(cmd-D)すると、マウスポインタの形が変わって任意の矩形領域をマウスのドラッグにより指定することを促されます。ドロー系アプリケーションなどでお馴染みの方法、つまり、左上から右下にかけてドラッグすることで矩形領域を指定します。この操作が終わると同時に、指定した矩形領域に含まれるビットマップ画像はモーフとして切り出されるはずです。

    Formは、ビットマップ画像を表わすオブジェクトが属するクラスで、fromUserメッセージを送ると、画面の任意の矩形領域のビットマップ画像をインスタンスとして返します。asMorphメッセージは、レシーバと等価、あるいは類似のモーフを生じさせ、それにopenInHandメッセージを送ることで画面に呼び出すと同時に、マウスで“つかんだ”状態にすることができます。

    ここで注意したいのは、asMorphメッセージは、Formではなく、Form fromUserの結果、つまりFormのインスタンスに送られる、ということです。同様に、openInHandは、FormでもFormのインスタンスでもなく、FormのインスタンスにasMorphを送った結果の返値、すなわち、Formのインスタンスと等価な画像モーフに対して送られます。余談ですが、asMorphはFormのインスタンスだけでなく、文字列などにも送ることができます。この場合、等価な文字列モーフ(StringMorph)のインスタンスが作られます。

    ‘This is a pen.’ asMorph openInHand

    話を戻します。10行目の最後に、式の区切りを意味するピリオドを追加し、先の式(Form fromUser …)を11行目として続けます。すべての行をあらためて選択してからdo it(cmd-D)をしてみましょう。絵を描いた後、shiftを押すと同時に矩形領域の選択が促され、それに従うと指定した矩形領域に含まれる絵を切り取ったモーフを手にすることができるはずです。

    モーフではなく、指定した矩形領域に含まれる絵をファイルとして保存するにはasMoprh、openInHandの代わりに次のメッセージ「writeJPEGfileNamed:’image.jpg’」をFormのインスタンスに送ります。パラメータで指定したファイル名でビットマップ画像をJPEGファイルとして保存することが可能です。

    Form fromUser writeJPEGfileNamed: ‘image.jpg’

     任意のファイル名で保存したければ、標準入力欄(fill in the blank)を使います。

    FillInTheBlank request: ‘Filename?’ “=> (入力した文字列) ”

    描く前の画面のクリア、描き終わった後の画面のリストアの処理を加え、出来上がったスクリプトはこんなかんじになります。

    | pen form |
    pen _ Pen new.
    pen defaultNib: 3.
    pen color: Color red.
    Display fillWhite.                     "画面のクリア"
    [Sensor shiftPressed] whileFalse: [
       | position |
       position _ Sensor peekPosition.
       Sensor redButtonPressed
          ifTrue: [pen goto: position]
          ifFalse: [pen place: position]].
    form _ Form fromUser.                  "描画のformへの束縛"
    ActiveWorld restoreMorphicDisplay.     "画面のリストア"
    form writeJPEGfileNamed: (FillInTheBlank request: 'Filename?')

     次回から、システムブラウザ(GUI)を使ったクラスやメソッドの定義のしかたを解説します。

    サポートページ:
    http://squab.no-ip.com:8080/mosaren/

    小池邦人の「Carbon API 徒然草」(2004/08/27)

    ウィンドウにイベントハンドラを実装

    今回は、ウィンドウに実装するイベントハンドラの例題として、前回紹介したアバウトウィンドウを表示するためのopenAboutWindow()ルーチンについて解説します。アバウトウィンドウはアプリケーションメニューの「MOSAについて…」を選択すると表示されます。アプリケーション自身に実装したイベントハンドラが、コマンドIDとして’abou’を受け取ることでopenAboutWindow()が実行される仕組みです。アバウトウィンドウの雛形オブジェクトは、先んじてNibファイル(main.nib)内に用意しておきます。オブジェクト名はAboutWindowです。

    Interface BuilderのToolsメニューから「Show Info」を選び、オブジェクト情報を表示してみると、Window Class:Modal、Theme:Default、Position:Alert Positionと設定されています。これは、昔で言うところのダイアログ(Dialog)ウィンドウを準備したことになります。アバウトダイアログには「Web」ボタンと「OK」ボタンが配置されており、それぞれに’WWW!’と’OK ‘のコマンドIDが割り当てられています。「Web」ボタンでは筆者ホームページの表示を、「OK」ボタンではダイアログ表示の終了(閉じる)を実行できます。ダイアログは一度表示されると、それを閉じるまで後ろのウィンドウと切り替えることはできません。Mac OS 9の時代ならば、こうした処理にDialog ManagerのAPIを使っていたのですが、Nibファイルを使用したCarbonアプリケーションでは、通常のウィンドウとまったく同様に扱うことが可能となりました。

    short openAboutWindow(void)
    {
        short        ret=1;
        WindowRef    wptr;
    
        if( ! createMyDialog( " pAboutWindow",'ABOU',&wptr ) )  // ダイアログ作成
        {
            setupDialogWindowEvent( wptr );             // イベントハンドラの実装
            TransitionWindow( wptr,kWindowZoomTransitionEffect,
                                 kWindowShowTransitionAction,NULL );  // 表示開始
            ret=noErr;
        }
        return( ret );
    }
    
    short createMyDialog( Str255 name,OSType wid,WindowRef *wptr )
    {
        short        ret=1;
        CFStringRef  cref;
        IBNibRef     nref;
    
        *wptr=NULL;
        if( ! CreateNibReference( CFSTR("main"),&nref ) )  // Nibファイルを読み込む
        {
            if( cref=CFStringCreateWithPascalString( NULL,name, // オブジェクト名を
                               CFStringGetSystemEncoding() ) )  // CFStringRefに変換
            {
                if( ! CreateWindowFromNib( nref,cref,wptr ) )   // ウィンドウの作成
                {
                    SetWRefCon( *wptr,wid );  // ウィンドウ識別値(ABOU)を登録
                    ret=noErr;
                }
                CFRelease( cref );
            }
            DisposeNibReference( nref );
        }
        return( ret );
    }
    


    openAboutWindow()は、Nibファイルに登録されているアバウトダイアログのオブジェクト名(AboutWindow)を、汎用ダイアログ作成ルーチンのcreateMyDialog()へ渡します。ただし、この時点では、ウィンドウは作成されただけで表示はされていませんので注意してください。続いてsetupDialogWindowEvent()を実行し、このダイアログにイベントハンドラを実装します。最後にTransitionWindow()を呼んだ時点で初めてウィンドウがオープンされます。以下が、ダイアログにイベントハンドラを実装しているsetupDialogWindowEvent()ルーチンです。

    void setupDialogWindowEvent( WindowRef window )
    {
        EventTypeSpec  list[]={
                                  { kEventClassCommand, kEventCommandProcess },
                                  { kEventClassCommand, kEventCommandUpdateStatus }
                                };
    
        InstallWindowEventHandler( window,myDialogWindowEventHandler,
                                        GetEventTypeCount(list),list,window,NULL );
    }
    


    ここでは、2種類のイベントに対応できるようなEventTypeSpecリストが作成されています。kEventCommandProcessの方はダイアログのボタンのコマンドIDを受け取るため、もうひとつのkEventCommandUpdateStatusの方は、メンテナンス(状況によりメニュー項目を利用可、不可に切り替える)が必要であるメニューのMenuRefを受け取るためです。アプリケーション自身にハンドラを実装する場合にはInstallApplicationEventHandler()を使いましたが、今回はウィンドウへの実装なので、代わりにInstallWindowEventHandler()を利用していることに注目してください。また、この時にuserDataとして対応するウィンドウのWindowRefを渡しておきます。これにより、処理対象となるウィンドウをハンドラルーチン側で簡単に認識することが可能となります。以下が、アバウトダイアログに実装されたイベントハンドラルーチンのmyDialogWindowEventHandler()です。

    pascal OSStatus myDialogWindowEventHandler( EventHandlerCallRef myHandler,
                                                   EventRef event,void* userData )
    {
        OSStatus        ret=eventNotHandledErr;
        unsigned long   ekind;
        WindowRef       wptr;
        long            cls;
        HICommand       cmd;
        Str255          str;
    
        cls=GetEventClass( event );   // イベントのクラス名を得る
        ekind=GetEventKind( event );  // イベントの種類を得る
        wptr=(WindowRef)userData;     // 処理対象ウィンドウのWindowRefを得る
        if( cls==kEventClassCommand ) // Carbon Eventのクラスはコマンド
        {
            switch( ekind )
            {
                case kEventCommandProcess: // コマンドIDが届く
    
                    GetEventParameter( event,kEventParamDirectObject,typeHICommand,
                          NULL,sizeof(HICommand),NULL,&cmd );   //コマンドIDを得る
                    switch( cmd.commandID )
                    {
                        case 'www!':  // 「Web」ボタンが押された
    
                            GetIndString( str,128,2 ); // STR#リソースからURLを得る
                            openURL( MY_SIG,str );     // ブラウザによるURLの表示
                            ret=noErr;
                            break;
    
                        case 'ok  ':  // 「OK」ボタンが押された
    
                            DisposeWindow( wptr ); // ダイアログを閉じる
                            ret=noErr;
                            break;
    
                        break;
                    }
                    break;
    
                case kEventCommandUpdateStatus: // メニューのメンテナンス要求が発生
    
                    GetEventParameter( event,kEventParamDirectObject,typeHICommand,
                          NULL,sizeof(HICommand),NULL,&cmd );  // MenuRefを得る
                    ret=mainteDialogMenu( wptr,cmd.menu.menuRef );
                    break;
            }
        }
        return( ret );
    }
    


    ダイアログのイベントハンドラであるmyDialogWindowEventHandler()内は、以前に紹介したmyApplicationEventHandler()とそっくりです。コマンドIDとして’www!’が届いた時には、ユーザが「Web」ボタンを押したことを意味しますので、以下のopenURL()ルーチンを実行します。openURL()で使われているICLaunchURL()は、Internet Config 2.0に属するAPIで、システムに登録されているウェブブラウザにURLを渡し、そのサイトを表示します。また、コマンドIDとして’ok ‘が届いた場合には、ユーザが「OK」ボタンを押したことを意味しますので、DisposeWindow()を実行してダイアログウィンドウを閉じます。

    short openURL( OSType sig,Str255 url )
    {
        long          st,ed;
        short         ret=1;
        ICInstance    inst;
        Str255        str;
    
        *str=0;
        if( ! ICStart( &inst,sig ) )
        {
            st=0;
            ed=url[0];
            ret=ICLaunchURL( inst,str,(char*)&url[1],url[0],&st,&ed );
            ICStop( inst );
        }
        return( ret );
    }
    


    今回は、イベントハンドラルーチンのウィンドウへの実装方法を解説しました。次回は今回の処理を参考にしながら、メインウィンドウ(CatalogWindow)をオープンするためのnewCatalogWindow()ルーチンへと話を進めることにします。

    つづく

    「Behind the WebObjects」  第26回  田畑 英和

     前回はERChangeNotificationJMS(以下ERCN)のセットアップ方法を解説しましたがいかがでしたでしょうか。最新版のOpenJMSに対応するためにはファイルの差し替えなどが必要になり少し手間がかかりますが、手間をかけた分のメリットは十分あるかと思います。今回はERCN解説の最後としてカスタマイズの設定方法やOpenJMSの自動起動についてご紹介いたします。

    ERCNのカスタマイズ

     PropertiesファイルによりERCNの挙動をカスタマイズすることができます。ERCNのプロジェクト内にPropertiesファイルのサンプルがありますので、こちらをもとに解説していきましょう。

    ・サンプルファイル
    ERChangeNotificationJMS/Documentation/SampleProperties.txt

    ◇serverHostName

     まずは”serverHostName”です。このパラメータを指定することで別サーバ上で稼働しているOpenJMSに接続することができます。デフォルトではlocalhostとなっているところをOpenJMSが稼働しているサーバに書き換えてください。これでアプリケーションサーバとは別マシンでJMSサーバを運用することができるようになります。
     当然接続先に指定したマシン上ではあらかじめOpenJMSが稼働している必要がありますが、Project WONDER2.0のERCNではもしJMSサーバへの接続が失敗した場合には、再接続処理をおこなうなど安定性を向上する機能が追加されています。

    # The host name that the JMS server is running on
    er.changenotification.jms.serverHostName = localhost

    ◇entitiesNotToSynchronize

     ERCNを使用するとデフォルトではすべてのEOの変更に対してJMS経由での同期処理がおこなわれますが、この”entitiesNotToSynchronize”パラメータを指定することにより特定のEntityのEOを同期処理の対象から外すことができます。
     例えば以下のように設定しておけば”TalentPhoto” EntityのEOを同期の対象から外すことができます。変更される機会が少ないEntityなどは処理対象から外しておけばEOの同期処理にかかる負荷を下げることができます。

    # Entities *not* to synchronize
    er.changenotification.entitiesNotToSynchronize = (TalentPhoto)

    ◇changeTypesToTrack

     ERCNがEOの同期をおこなうタイミングは、EOの追加/変更/削除の3つがありデフォルトではすべてのタイミングで同期処理が実行されます。*注1
     ”changeTypesToTrack”を設定することにより同期処理を実行するタイミングを指定することができます。

    # Change types to track; Can contain inserted, updated and deleted.
    er.changenotification.changeTypesToTrack = (inserted, updated, deleted)

    *注1
    ERCNが実際にEOの同期をおこなうのは「変更」の場合のみです。追加/削除のタイミングではフレームワーク側で同期処理はおこなわれません。追加/削除のタイミングで処理をおこなう場合はアプリケーション側での対応が必要になり、具体的にはERCNSubscriberDelegateインターフェースを用いて追加/削除時に処理をおこなうクラスを作成し、ERCNSubscriberのsetDelegate()メソッドを用いてセットしておく必要があります。

    OpenJMSの自動起動

     ERCNを使用した場合、アプリケーションの起動時にJMSサーバへの接続がおこなわれます。つまりアプリケーションの起動時にはあらかじめJMSサーバが起動している必要があります。
     そこでシステム起動時にOpenJMSを起動するためのスクリプトがあらかじめ用意されています。*注2

    ・起動スクリプト(Project WONDERのソースに収録)
    ERChangeNotificationJMS/Support/StartupItemsMacOSX/OpenJMS

     /Library/StartupItems/に、StartupItemsMacOSXフォルダ内にあるOpenJMSフォルダをコピーしてください。これでシステム起動時にOpenJMSが自動起動するようになります。
     実際にOpenJMSを起動させている起動スクリプトはOpenJMS/OpenJMSになりますが、うまく動作しない場合はパーミッションの実行権限が与えられているかを確認してください.

    *注2
    起動スクリプトはopenjms-0.7.6.1に対応していません。対応するためには以下のように起動と停止のコマンドを書き換えてください。

    ・StartService
    $OPENJMS_HOME/bin/startup.sh -config $OPENJMS_HOME/config/$CONFIG_FILE &
    ・StopService
    $OPENJMS_HOME/bin/shutdown.sh -config $OPENJMS_HOME/config/$CONFIG_FILE

     さて、これまで3回にわたってERCNの解説をおこなってきましたがいかがでしたでしょうか。ERCNはもともとOpenJMSを利用して開発されていますが、JMSはJavaの仕様であり、OpenJMS以外にもJMSを実装したプロダクトは存在しますので、他のJMSサーバを利用することも可能です。
     マルチインスタンスでの運用をおこなうには、あらかじめEOの同期が適切におこなわれるような設計でアプリケーションを開発しておく必要がありますが、このERCNを用いれば、アプリケーション側のコードを変更することなくインスタンス間でのEO同期が実現できますので非常に強力です。

    お知らせ

     WebObjectsの運用管理トレーニングがスタートします。詳しくは次のURLを参照してください。
    http://www.event21.ne.jp/apple/woomc.html

    ニュース・解説

    今週の解説担当:新居雅行

    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    ┃ネットワーク経由でコアダンプを取得する方法
    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    Mac OS X 10.3より可能になった、カーネルコアのダンプを他のサーバマシンに転送する機能の使い方を紹介した文書が公開されている。カーネルで問題が発生した場合には、コアダンプを検討して問題点を突き止めると言った作業が行われる。あるコンピュータで設定を行えば、カーネルパニックのときなどにコアダンプを他のホストに送付する機能が働く、受け取る側でも設定を行っておけば、ダンプをサーバで受け取るということができる。これらの機能を可能にするための設定と、コアダンプを見ながらのデバッグについての解説がある。

    Technical Note TN2118: Kernel Core Dumps
    http://developer.apple.com/technotes/tn2004/tn2118.html

    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    ┃Mac OS X向けのPHP5
    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    Marc Liyanage氏によるサイトEntropy.chで、PHP5のMac OS X向けのパッケージが公開されている。PHP5は最近になって正式に公開されたサーバサイドのスクリプト環境で、Mac OS X環境に考慮しApache 1.3ベースで稼働するものをビルドしてパッケージにしている。以下の「PHP Apache Module」で、Ver.5.0.1のパッケージを配布しているが、フォーラムの書き込みもチェックしておいた方がいいだろう。PHP5では、オブジェクト指向プログラミングの機能が充実し、SQLiteが組み込まれるといった変化がある。PHP4からの変更点が大きいため、多くのサイトはしばらくは以前のバージョンを使い続ける事になる模様だ。

    Package for PHP 5.0.0-13 available
    http://www.entropy.ch/phpbb2/viewtopic.php?t=1446
    PHP Apache Module
    http://www.entropy.ch/software/macosx/php/

    MOSAからのお知らせと編集後記は割愛します

    MOSA Developer News   略称[MOSADeN=モサ伝]
    Apple、Mac OSは米国アップルコンピュータ社の登録商標です。またそのほかの各製品名等はそれぞれ各社の商標ならびに登録商標です。
    このメールの再配信、および掲載された記事の無断転載を禁じます。
    http://www.mosa.gr.jp/
    Copyright (C)2004-2006 MOSA. All rights reserved.

  • MOSA Developer News[MOSADeN=モサ伝]第125号

    2004-08-24

    目次

    • SqueakではじめるSmalltalk入門   第7回  鷲見正人
    • 藤本裕之のプログラミング夜話 #51
    • 高橋真人の「プログラミング指南」 第50回
    • ニュース・解説

    SqueakではじめるSmalltalk入門   第7回  鷲見正人

     本連載では、名前はよく耳にしていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。今回は、通常のプログラミング言語では構文として用意されているループや条件分岐が、すべてをメッセージ式のみで表わそうとするSmalltalkにおいて、どのように実現されているかを解説します。

    (3 > 4) ifTrue: [5] ifFalse: [6] “=> 6 ”

     この式は「3」が「4」より大きければ「5」、そうでなければ「6」を返します。もちろん、3は4より大きくないので、ブロック[6]の評価結果である「6」を返すはずです。この式はprint it(cmd-P)で実際に動作を確認できるので試してみてください。ここで、式「3 > 4」は、レシーバ「3」にメッセージ「> 4」を送って「false」を返します。なお、メッセージ式において、単項メッセージは二項メッセージに、二項メッセージはキーワードメッセージに優先して評価されます。したがって、(3 > 4)の括弧は、ここでは読みやすくするために付けましたが、実際には不要です。

    3 > 4 ifTrue: [5] ifFalse: [6] “=> 6″

    と書いても問題なく評価されます。同じくキーワードメッセージに優先される単項メッセージも同じです。

    (3 isZero) ifTrue: [5] ifFalse: [6] “=> 6 「3 isZero」は3が0ならtrue”
    3 isZero ifTrue: [5] ifFalse: [6] “=> 6 括弧は不要”

    しかし、

    (3 isDivisibleBy: 4) ifTrue: [5] ifFalse: [6] “=> 6 ”

    のように、レシーバであるtrueやfalseを産生する式が、キーワードメッセージの場合(あるいは、もっと複雑な式の場合)は括弧は必要です。たとえば上の例で、もしこの括弧がないと、

    3 isDivisibleBy: 4 ifTrue: [5] ifFalse: [6]

    となり、3への「isDivisibleBy: 4 ifTrue: [5] ifFalse: [6]」というメッセージ送信と解釈されてしまいます。当然、#isDivisibleBy:ifTrue:ifFalse:などというセレクタは登録されていないのでこうしたコードがあっても、例外が生じて処理は中断しますし、そもそも評価時(メソッドならコンパイル時)に警告が出るので、ミスしたことには容易に気付くことができるはずです。

     話を戻します。前式は、(3 > 4)が常にfalseを返すので、

    false ifTrue: [5] ifFalse: [6] “=> 6 ”

    と書き換えても結果は同じです。レシーバ「false」に送られるメッセージ「ifTrue: [5] ifFalse: [6]」は、#ifTure:ifFalseというセレクタ(メソッド名)と、[5]と[6]という2つのパラメータからなります。同じメッセージを、試しにtrueに送ってみましょう。

    true ifTrue: [5] ifFalse: [6] “=> 5 ”

    今度はブロック[5]の評価結果である「5」が返ります。

     ここで条件分岐について、もう少し掘り下げて考えてみることにします。メッセージ「ifTrue: [5] ifFalse: [6]」によって起動される#ifTrue:ifFalse:というメソッドの中身はどんなものか、想像してみてください。オーソドックスには、レシーバがtrueなら第1パラメータとして与えられた真時ブロックを、falseなら第2パラメータの偽時ブロックを遅延評価して結果を返値として返す…というような手続きを記述した関数(メソッド)を用意すればよいように思います。しかし、Smalltalkではこれとは別のアプローチをとっています。

    Smalltalkでは真偽値(true、false)もオブジェクトです。これは、それぞれが「ifTrue: [5] ifFalse: [6]」というメッセージを受信できることからもお分かりいただけると思います。trueはクラスTrueの、falseはクラスFalseの、それぞれ唯一のインスタンスです。

    メソッド#ifTrue:ifFalse:は、実は、クラスTrue、クラスFalseに別々に定義されています。Smalltalkプログラマのあいだでは、クラスTrueに定義されているメソッド#ifTrue:ifFalseを表わすのに「True >> #ifTrue:ifFalse」のように書く習慣があるので、これに従うと、#ifTrue:ifFalseという名のメソッドは、True >> #ifTrue:ifFalseと、False >> #ifTrue:ifFalseの2つが存在する…ということになります。

    trueはメッセージ「ifTrue: [5] ifFalse: [6]」を受けると、True >>#ifTrue:ifFalse:を起動し、falseはFalse >> #ifTrue:ifFalse:を起動します。True >> #ifTrue:ifFalse:には、第2パラメータを無視し、第1パラメータとして渡されるブロックを評価した結果を返す手続きが記述されています。False >> #ifTrue:ifFalse:には逆、つまり、第1パラメータを無視し、第2パラメータであるブロックを評価した結果を返す手続きだけが記述されています。実際に、True >> #ifTrue:ifFase:、あるいは、False >>#ifTrue:ifFalse:のソースコードを見て、実際にそうなっているか確認してみましょう。

    適当な場所に「ifTrue:ifFalse:」と入力後、選択してからimplementors of it(cmd-M)します。すると、図に示すような2ペインのウインドウが現われるので、上のペインからTrue ifTrue:ifFalse: {controlling}、あるいは、False ifTrue:ifFalse: {controlling}と書かれた選択肢をクリックして選択すると、下のペインにそれに対応するメソッドのソースを呼び出すことができます。

    [fig.A]#ifTrue:ifFalse:メソッドのソースを閲覧するためのウインドウ
    http://squab.no-ip.com:8080/mosaren/uploads/07a.png

    [fig.B]True >> #ifTrue:ifFalse:のソースコード
    http://squab.no-ip.com:8080/mosaren/uploads/07b.png

    [fig.C]False >> #ifTrue:ifFalse:のソースコード
    http://squab.no-ip.com:8080/mosaren/uploads/07c.png

     Smalltalkのメソッドのソースコードの読み方をここで簡単に説明しておきましょう。太字で書かれた1行目、

    ifTrue: trueAlternativeBlock falseAlternativeBlock

    は、メッセージパターンと呼ばれるもので、このメソッドを呼び出すためのメッセージの記述方法を示したものです。メソッド名(セレクタ。ここでは#ifTrue:ifFalse:)とパラメータ変数(trueAlternativeBlockとfalseAlternativeBlock)の宣言も兼ねています。2行目と3行目にはコメントとしてこのメソッドの説明が書かれています。

    3行目が、短いですがメソッド本体のソースコードです。「↑」は「^」(ハット)で入力できる記号で、メソッドの終了とそのときの返値を明示的にするときに使います。ちなみに返値を明示的にしないときはself(レシーバ自身)が返値として返ります。なお、Smalltalkには返値のない関数(メソッド)というものはありません。

    #ifTrue:ifFalse:メソッド本体のコードを改めて見ていただくと、受け取ったブロックのうち一方を単純に評価(メッセージ「value」を送信)して値を返しているだけであることが、はっきりと見てとれると思います。条件分岐をメッセージ送信で表現することも特殊なら、その実装方法も特殊で、しかもとてもシンプルにそれを実現していることはたいへん興味深いですね。(実はこの話には“大きな嘘”があります。しかし、コンパイラの挙動やバイトコードに言及する必要があるので、またの機会に…)

    次回は、サンプルプログラムに話を戻して、描いた絵を保存する機能拡張を施します。

    サポートページ:
    http://squab.no-ip.com:8080/mosaren/

    藤本裕之のプログラミング夜話 #51

     承前、ということになる。前回はC++の多重継承が「空飛ぶコーモリはケモノでもあるがトリでもある」としちゃいがちな機構であり、ヘタに使うと(言うまでもないがうまく使えば問題はない、というかそもそもは「うまく使われる」ためにあるんだからね)スパゲティ・プログラムのOOP版……うまい比喩が思いつかぬが人知を超えた実験料理みたいなものになっちまうという話を書いた。これに比べて多重継承を許さないObjective-Cはそういう余地がないのでオレはこっちの方が好きである、と。
     ここでOOP理解はイマイチながらそれなりに頭のスルドいあなたは当然以下のような疑問を持ったはずである。すなわち、
     「トリとケモノを多重継承せずにどうやってコーモリに空を飛ばせっつうのだ?」
    と、いうことですね。今回はその話。

     確かにコーモリもトリも空を飛ぶ。だけどそれを言ったらセミだってミツバチだって飛行機やヘリコプター、スーパーマンだって銃弾だって飛ぶんである。ミミズだっておけらだってあめんぼだってみんなみんな生きているんだトモダチなんである。ミミズとおけらは飛ばないけど……。
     つまりはこういうことだ。「飛べる」という能力はトリだけの専売特許ではない。トリというクラスに固有の(ゆえにそれを継承するにはサブクラスするしかない)能力ではなく、クラス横断、複数のクラスにまたがって保持される類いの能力である。そしてその「飛行能力」というモノ自体はなんらの実体を持たない抽象的な概念である、わかりますか。
     C++やJavaなどの言語にはこうした抽象概念を扱うための抽象クラス(abstract class)という仕組みが用意されている。例えば「飛べる」という抽象クラスは以下のように定義する。

    class ItCanFly {
    /*  variables declaration it needs... */
    public:
      virtual void fly(void) = 0;    /* pure viratual function */
    }

     関数 fly() の定義部分にコメントしているが、この例のように「=0」(こいつを純粋指定子という)をくっつけて宣言した関数を「純粋仮想関数」といい、この純粋か相関数を一個でも持つクラスはそのまま自動的に抽象クラス、ということになってるんだが、そういう用語なんか暗記しなくてもいい(実はオレもここの用語は参考書で確認しながら書いた)。それよりこの抽象クラスというものの、文字通り「抽象性」というものをよっく味わってもらいたいのだ。
     他のことに関しては通常のクラスと同じでありながら、このクラスの使用にはひとつだけできないことがある。それは「直接このクラスのインスタンスを生成できない」ということ、つまりこの仕組みは例えば「飛べる」のような純粋に抽象的な能力を「多重継承を」を使って個々のオブジェクトに付与するためにあるのだ。以下に「コーモリを『飛べるケモノ』とする具体的な定義」を示しておく。

    class Bat : public Animal,  ItCanFly {
    /* variables declaration it needs... */
    public:
      void fly(void);    /* You must declar this function concretely */
    }

     そしてこのコーモリのように抽象クラス「飛べる」を継承したクラスは抽象クラスの持つ純粋仮想関数を具体的に定義しなければならない。上で見たようにトリも飛行機もスーパーマンもそしてコーモリも飛ぶが、その方法はいろいろであり、それを記述する責任はサブクラス側にゆだねられている。

    ここまで説明すれば「コーモリを飛ばすためにトリを多重継承させる」ことの愚がわかってもらえたと思う。たまたまコーモリはトリと同じように「羽ばたいて」飛ぶが、やってることは「コーモリを飛ばすためにスーパーマンを多重継承しちゃう」のと同じことなんだってば……。え、それがバットマンだって? バットマンって飛べたっけ?
    (2004_08_14)

    高橋真人の「プログラミング指南」第50回

    UNIXとしてのMac OS X

    〜導入のお話〜

     こんにちは、高橋真人です。さて、思いつくままに駄文を書き連ねてきたこの連載ですが、いつの間にか50回を数えることになりました。
     区切りのよい数を迎えたこととは全く関係ありませんが、かねてお話ししていたようにオブジェクト指向に関するお話に関してはいったんおしまいにし、今回からは少し切り口を変えてちょっとした役に立つ(かもしれない)小ネタをいくつか紹介していきたいと思います。とはいえ、私の中にためてきた小ネタで果たしてどのくらいの期間持つのかは皆目検討が付きませんので、再び突然の路線変更などということもあるかもしれません(笑)。
     さて、当面は今回の表題にもうたっているように、Mac OS XのUNIX的な側面に関して注目してのお話を展開していこうと思っています。
     ただ、UNIX的な側面ということに関しても、最近ではMac OS XのUNIX面について解説している書籍も増えてきましたし、雑誌などでも特集が組まれることも多いので、それと同じではあまり面白くありません。それに、LinuxやOPENSTEPの環境でバリバリにやってきた方々に役立つような情報は到底私に提供できるわけもありませんので、ここはひとつ「プログラミング指南」らしく、プログラミング初心者の方にメリットのありそうな情報という観点で行きたいと思います。

    「MacがUNIXになる」。そんな話を聞いた数年前、私はかなり興奮したのを覚えています。Macにある程度慣れたころから、「そのうちUNIXに手を出してみたい」と思って、Linuxで遊ぶためにDOS/Vマシンを購入した(新しいマシンを買ってしまったため、Linuxがまだ対応しておらず、インストールの途中で撃沈)ことさえあったくらいですから、わざわざ新たにマシンを用意せずとも「Macで何でもできる」という状態は私にとってはまさに夢でした。
     もっとも、当時はまだユーザーとしての視点しかなく、プログラミング的にどのようなメリットがあるのかなどということは考えてもみませんでした。ですが、最近になって、仕事で特にネットワークがらみの仕組みが必要になることが多く、改めてネットワークプログラミングについて勉強すると、この辺のメリットを実感することは多いのです。
     たとえばUNIX向けとうたってある本であれば、特にMac OS X対応となっていない本であっても、掲載されているサンプルソースを打ち込んでみるとほとんど修正も必要なく動作したりすることは多く、そんな時にこそ「夢が叶ったなぁ」と実感するのです。
     このように夢の環境が身近なところにあるにもかかわらず、単に従来のMac OSの延長として使っている人がことのほか多いようです。もちろん安定性だとかプリエンプティブマルチタスクという、さんざん強調されてきた特徴も、生産性の貢献という意味で大きな価値があることは疑いのないところです。
     ですが、PostgreSQLなどのちまたで人気のオープンソースのデータベースがネイティブで動作するとか、ApacheやPerl、Ruby、PostfixだのといったLinuxの世界でもとても人気のある製品が最初から標準機能として備わっているという、とても「おいしい」状態を興味を持たずに放っておくのももったいない話だと思うのです。
     そういう人たちの中に、こんなことをおっしゃる方がいます。
     「確かに、世の中にはUNIXという切り口での解説記事や書籍が出ていて、前書きには『Mac OS Xでも動作するので、必要な部分を読み替えろ』と書いてある。しかし、いざ実践しようとするとその読み替えをどのようにすればよいのかが皆目検討つかない。また、書き込み権限がどうだのと、インストールすらままならない場合もある」
     確かに、慣れない人にとってUNIXの文化は難しい部分もあるようです。かなり歴史の長いOSですから、「知っている人しか知らない」状態の知識というものも多く、そこが初心者にとっては敷居を高くする要因であるのかもしれません。
     そんなわけで、皆さんと同じ「普通のMacユーザー」状態からスタートし、試行錯誤しながらも現在ではMacのUNIX機能をそれなりに享受することのできている私が自分の経験から取得したワザをいくつかご披露できれば、と思っているのです。

    ニュース・解説

    今週の解説担当:小池邦人

    Carbon ドキュメント & サンプル & SDK ナビゲーション(2004/08/20)

    【開発環境】

    Apple社からXcode 1.5の正式版が発表されました。すべての開発環境を含んだ「Xcode Tools 1.5」は、ADCメンバーサイトからダウンロードすることができます。新しい機能や改良点は、Xcodeを最初に起動した時に表示されるRelease Notesを読めば確認できます(Helpメニューからも表示可能)。Xcode Tools全体の詳細については、以下のToolsサイトを参照してください。ちなみに、Interface Builderはv1.2から何も変化がありませんでした(涙)。ちゃんと開発は継続しているのでしょうか?

    http://devworld.apple.com/tools/xcode/

    Metrowerks社のダウンロードサイトに「CodeWarrior Development Studio for Mac OS, Version 9.3 Update」が登録されました。さっそく筆者の開発環境もv9.3へとアップデートしてみました。開発中の色々なプロジェクトを再コンパイル&リンクしてみたのですが、今のところ問題は発生していません。Apple社の最新の開発環境とv9.2の組み合わせでは、プロジェクトにcrt1.oを加えているとリンクが正常に終了しない問題が発生していましたが(mwcrt1.oの方は大丈夫)、v9.3ではそれもちゃんと改善されています。

    WWDC2004ではブースも出展していなかったMetrowerks社ですが、まだMacintoshユーザは忘れられていなかったようです(笑)。コンパイラのG5への最適化を含め、これからもちゃんとしたサポートの継続を望みたいところです。v9.3 Updaterを入手するには、以下のMetrowerks社のダウンロードサイトへ入り、「Updates and Patches」のリストから「CodeWarrior for Mac OS 9」(Mac OS 9という意味ではなくバージョン9の意味)を選択してください。v9.3 Updaterの容量は112M Byteもありますので、ダウンロード時間には注意しましょう。

    「CodeWarrior Development Studio for Mac OS, Version 9.3 Update」

    http://www.metrowerks.com/MW/download/default.asp

    ソフトウェア・アップデートから「Java 1.4.2 Update 1」がダウンロードできるようになりましたが、それに対応してADCメンバーサイトに「java142update1tools」が登録されました。また、Apple社のReleaseサイトには、以下の2つのドキュメントが追加されています。

    「Introduction to Java 1.4.2 Release Notes」(PDFあり)

    http://developer.apple.com/releasenotes/Java/Java142RN/index.html

    「Introduction to Java 1.4.2 Update 1 Release Notes」(PDFあり)

    http://developer.apple.com/releasenotes/Java/Java142RNUpdate1/index.html

    【テクニカルドキュメント】

    前回から8月20日の期間中、Apple社のDocumentationサイトには新規ドキュメントが9つ登録されました。加えて、デベロッパ向けの読み物として以下の3つの解説が登録されています。

    「Jar Bundler」(PDFあり)
    「Plug-ins」
    「Mac OS X Assembler Guide」(PDFあり)
    「Remote Debugging in Xcode」
    「Streams」
    「Text System User Interface Layer」(PDFあり)
    「Xcode Build System」
    「Coding Guidelines」
    「Transferring Data With URL Access Manager」(PDFあり)

    http://developer.apple.com/documentation/index-rev-date.html

    「Carbon Pasteboards: Enhancing Data Sharing」(読み物)

    http://developer.apple.com/carbon/pasteboards.html

    「Universal Access: Computers That Everyone Can Use」(読み物)

    http://developer.apple.com/accessibility/universalaccess.html

    「Introducing Xcode 1.5: Improving Speed and Workflow」(読み物)

    http://developer.apple.com/tools/xcode/reviewxcode.html

    前回から8月20日の期間中、新規のテクニカルノートは2つ登録されましたが、テクニカルQ&Aの方はひとつも登録されませんでした。「Kernel Core Dumps」は、Mac OS X 10.3でカーネルパニックやハングアップが発生した時に、リモートでコアダンプを実行することでカーネルの状態を調べる方法が解説されています。

    TN2118「Kernel Core Dumps」
    TN2110「Identifying Java on Mac OS X」

    http://developer.apple.com/technicalnotes/index-rev-date.html

    【サンプルソースコード】

    前回から8月20日の期間中、Apple社のSample Codeサイトには、新しいサンプルソースコードが5つ登録されました。「CarbonSketch」は、QuickDraw APIからQuartz 2D APIへの移行を促すための例題としてWWDC2004のセッションでも紹介されていました。しかし、Apple社はこのレベルの例題を提示しておけば移行が可能だと本当に思っているのでしょうか(笑)。多くのQuickTime APIがいまだにGWorldベースなんですけどねぇ?

    「SpellingChecker CarbonCocoa Bundled」( Carbon関連)
    「BackgroundExporter」(QuickTime関連)
    「CFFTPSample」(CFNetwork関連)
    「CarbonSketch」(Quartz 2D関連)
    「ComplexPlayThru」(CoreAudio関連)

    http://developer.apple.com/samplecode/index-rev-date.html

    【デベロップメント SDK】

    前回から8月20日の期間中、Apple社のSDKサイトには新しいSDKはひとつも登録されませんでしたが、Mac OS X 10.3.5用の「Kernel Debug Kit」が登録されています。また、Darwinサイトにはプレビュー版 Mac OS X 10.4(Tiger)とMac OS X 10.3.5用の最新ソースが登録されました。

    「Kernel Debug Kit 10.3.5」

    http://developer.apple.com/sdk/

    「WWDC 2004 Developer Preview (Darwin 8.0b1 Source Code)」

    http://www.opensource.apple.com/darwinsource/WWDC2004/

    「Darwin 7.5 Source Code」

    http://developer.apple.com/darwin/

    MOSAからのお知らせと編集後記は割愛します

    MOSA Developer News   略称[MOSADeN=モサ伝]
    Apple、Mac OSは米国アップルコンピュータ社の登録商標です。またそのほかの各製品名等はそれぞれ各社の商標ならびに登録商標です。
    このメールの再配信、および掲載された記事の無断転載を禁じます。
    http://www.mosa.gr.jp/
    Copyright (C)2004-2006 MOSA. All rights reserved.

  • MOSA Developer News[MOSADeN=モサ伝]第124号

    2004-08-10

    目次

    • SqueakではじめるSmalltalk入門   第6回  鷲見正人
    • 小池邦人の「Carbon API 徒然草」
    • 「Behind the WebObjects」    第25回  田畑 英和
    • ニュース・解説

    SqueakではじめるSmalltalk入門   第6回  鷲見正人

     本連載では、名前はよく耳にしていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。例として提示した簡単なペイントスクリプトの解説をしていますが、今回は、ループや条件分岐の部分を取り上げます。

    前回の解説では、4行目まででは「pen」という一時変数を用意し、Penのインスタンスをそれに束縛し、描く線の太さと色をいずれも、主にメッセージ送信により実現していることを示しました。どんなオブジェクトに、どのようなメッセージを送って、何をさせるのか…。“メッセージ指向”と呼ぶべきSmalltalkオリジナルの「オブジェクト指向」に身をゆだねるとき、ユーザーは常にこれらのことに意識を向けなければなりません。

    "01" | pen |
    "02" pen _ Pen new.
    "03" pen defaultNib: 3.
    "04" pen color: Color red.
    "05" [Sensor shiftPressed] whileFalse: [
    "06"    | position |
    "07"    position _ Sensor peekPosition.
    "08"    Sensor redButtonPressed
    "09"       ifTrue: [pen goto: position]
    "10"       ifFalse: [pen place: position]]

     “メッセージ指向”においては、通常のプログラミング言語では専用の構文を用意するループや条件分岐でも「オブジェクトに対するメッセージ送信」のスタイルで表現することをあくまで貫きます。このプログラムでは5行目から10行目に渡って記述されている「whileFalse: [...]」というメッセージ送信が“ループ”を、8行目から10行目に渡って記述されている「ifTrue: [...]ifFalse: [...]」というメッセージ送信が“条件分岐”を表わす例になっています。

    [ ]で括られる記述は、ブロック(BlockContext)と呼ばれる“処理”をオブジェクト化したもののリテラル式です。[ ]を使っていることからすぐに分かるように、Objective-Cはこの種のオブジェクトやそのリテラル記述はサポートしていません(リテラル記述を代えて同種のオブジェクトを提供する外部ライブラリ自体は存在します)。他方で、LISPなどに精通しておられるかたなら、無名関数(λ式)と同種のものだと言えばピンとくるはずです。

    ブロックについては追って詳しく解説を加えなければならないときが来ると思いますが、ここでは簡単に。[ ]で括られた一連の式はその場では評価されず、処理そのものとしてオブジェクト化され、変数に束縛したり、パラメータとして受け渡すなど第1級のデータとして扱うことが可能になります。たとえば、

    3 + 4

    という式は、そのまま評価してしまうと結果である「7」になってしまい、それを生み出す過程である「3 + 4」という処理としての性格は失われてしまいますが、

    [3 + 4]

    とブロックオブジェクトとして記述しておくことで、文字通り「3 + 4」という処理を表わすオブジェクトとして扱うことが可能になります。変数への束縛も可能です。メッセージ「value」を送信することで、中に含まれる処理の遅延評価を行なうことができ、結果の「7」を得ることができます。

    | block |
    block _ [3 + 4].
    block value “=> 7 ”

     ブロックがオブジェクトであり、メッセージの受信者(レシーバ)になることができる具体例は、件のプログラムの5行目にも見つけることができます。ここで、メッセージ「whileFalse: [...]」は、

    [Sensor shiftPressed]

    というブロックオブジェクトに送信されています。#whileFalse:は、レシーバのブロック内の評価値がfalseの間、パラメータのブロックの評価を繰り返すメソッドです。当然、レシーバの評価値がtrueを返す間だけ繰り返す#whileTrue:というメソッドもあります。ちなみに、論理反転のためのメッセージ「not」を使うことで、5行目は、次のように書き換えても同じ意味になります。

    “05″ [Sensor shiftPressed not] whileTrue: [

     Sensorにメッセージを送ることで、我々はその刹那のキーボードやマウスの状態を知ることができます(註)。メッセージ「shiftPressed」の送信では、シフトキーが押されているかどうかを真偽値(true、false)の返値として得ることが可能です。このことから分かるように、#whileFalse:、#whileTrue:を起動するメッセージのレシーバは、ブロックでも、特に真偽値を返すブロックであることが期待されます。たとえば、

    [true] whileTrue: []

    のような場合、レシーバは評価時に常にtrueを返すので、結果、無限ループになります。無限ループから脱するには、cmd-.(ピリオド)をタイプしてください。

     Sensorはクラスではなく、InputSensorあるいはEventSensorに属するインスタンス(システムを構成するオブジェクトのひとつ)を束縛するグローバル変数です。グローバル変数はいったん定義してしまえば、あとは宣言なしでいつでもどこででも使用できる変数で、大文字から始めるきまりになっています。実は、クラスもこのグローバル変数に束縛されているオブジェクトに過ぎません。

    8行目から10行目までがメッセージ送信によって表現された条件分岐の例です。8行目の、

    Sensor redButtonPressed

    は、評価の瞬間、マウスボタン(2ボタン以上のマウスなら左ボタン)が押されているかを真偽値で返す式です。この返値であるtrue、もしくはfalseに対して「ifTrue: 真時処理 ifFalse: 偽時処理」というメッセージを送ることで、通常のプログラミング言語における条件分岐をシミュレートしています。レシーバがtrueなら第1パラメータである真時処理ブロックを、falseなら第2パラメータである偽時処理ブロックを評価します。これで、マウスボタンが押されていれば、ペンを下げて移動し(描画)、押されていないときはペンを上げた状態で移動(マウスポインタへの単なる追従)という処理を表わしています。

    この#ifTrue:ifFalseの実装方法はおもしろいので、引き続いて次回、もう少し詳しく解説を加えたいと思います。

    註:ただしSensorは、Squeakの前身であるSmalltalk-80時代から引き継がれた、MVCと呼ばれる古いGUIフレームワーク(Cocoaでも、この亜種が採用されていますね)で使われていたグローバル変数で、バックワードコンパチビリティの目的で使用できているに過ぎません。現在のMorphicと呼ばれる新しいGUIフレームワークでは、より高機能なActiveHandを使うことが推奨されます。ここではコードを簡素化するため、あえてSensorを用いました。

    サポートページ:
    http://squab.no-ip.com:8080/mosaren/

    小池邦人の「Carbon API 徒然草」(2004/08/06)

    Standard Handlerを活用する

    前回、サンプルアプリケーションに実装したイベントハンドラルーチンを解説しました。その中で、ユーザがメニュー選択を行った場合には、メニュー項目に一対一で対応したコマンドID(Nibファイルに定義されている)がハンドラへ送られて来ると説明しました。再度、それを処理している部分をピックアップしてみます。

        witch( cmd.commandID )  // コマンドIDの種類を判断
        {
             case 'new ': // ファイルメニューの「新規」
    
                 newCatalogWindow( &wptr );  // 新規ファイルルーチン
                 ret=noErr;                  // ここでストップ
                 break;
    
             case 'open': // ファイルメニューの「開く...」
    
                  loadCatalogFile( &wptr );  // ファイルロードルーチン
                  ret=noErr;                 // ここでストップ
                  break;
    
             case 'abou': // アプリメニューの「MOSAについて...」
    
                  openAboutWindow();         // アバウト表示
                  ret=noErr;                 // ここでストップ
                  break;
    
             case 'quit': // アプリメニューの「MOSAを終了」
    
                  if( quitApplication() )   // アプリケーションの終了
                      ret=noErr;            // ここでストップ(終了はしない)
                  break;
        }
        break;
    


    この部分には、ユーザがアプリケーションメニューの「MOSAについて…」「MOSAを終了」、もしくはファイルメニューの「新規」と「開く…」を選択した時の処理が記述されています。ここで注目すべき点は、各ケースの出口でretにnoErr(ゼロ)が代入されていることです。このretは、イベントハンドラの最後にreturnに代入されてルーチンの「返り値」となっています。

    前回、Carbon Eventは各オブジェクトに実装されたイベントハンドラ間を階層にそって伝搬(継承)していくと説明しました。コントロールに実装されたハンドラからウィンドウのハンドラへ、そしてアプリケーションのハンドラへといった流れがあるわけです。しかし、ルーチンの返り値をnoErrにすると、Carbon Eventの伝搬はそのハンドラでストップします。つまり、「処理はここで終わったから、このCarbon Eventはもう次のイベントハンドラへは送るな!」という意味になるわけです。

    逆に、Carbon Eventの伝搬を継続(サッカーでのパスのスルーと同じ)させる場合には、noErrの代わりにeventNotHandledErrを返します。eventNotHandledErrはルーチンの最初でretに代入されていますので、処理内で再度何かを代入しなければ、これがディフォルトの返り値となります。

    OSStatus ret=eventNotHandledErr;

    以前にお話したかもしれませんが、送られてきたCarbon Eventに対応した処理は、必ずしもユーザが実装したイベントハンドラで実行されるとは限りません。ルーチンの返り値をeventNotHandledErrとし、Carbon Eventを次のハンドラへとスルーすると、そのCarbon Eventは最終的にはシステムが用意したイベントハンドラで処理されることになります。このイベントハンドラを「Standard Handler」と呼びます。

    例えばコマンドIDが’abou’のケースでは、openAboutWindow()でアバウトウィンドウを表示しています。ここでは、これ以上の処理をする必要がありませんので、retにnoErrを代入してCarbon Eventの伝搬にストップをかけています。さて、ここで簡単な実験をしてみることにします。まず、以下のようにopenAboutWindow();をコメント行にしたらどうなるでしょうか?当然、メニューを選択しても何も起こりませんね。

            case 'abou':
    
             //   openAboutWindow();
                  ret=noErr;
                  break;
    


    今度は、ret=noErr;をコメント行にしてみます。メニューを選択すると、なんとアバウトウィンドウが2つも表示されてしまいます!

            case 'abou':
    
                 openAboutWindow();
             //  ret=noErr;
                 break;
    


    最初にopenAboutWindow()で自分自身のアバウトを表示し、その後にCarbon EventをStandard Handlerへとスルーしたため、システム側でもディフォルトのアバウト表示が成されたわけです。ディフォルトのアバウト表示(Safariのアバウトがそう)は、Mac OS X 10.3(Panther)からアプリケーションのStandard Handlerに実装されました。つまり、個人的に凝ったアバウト表示をする必要がなく、ディフォルトアバウトで十分であれば、コマンドIDが’abou’のケースはわざわざアプリ側で処理する必要はないわけです(Mac OS X 10.3以降のみなので要注意)。このように、ユーザインターフェース・オブジェクトには、必ずシステム側で何らかのStandard Handlerが用意されており、適切なディフォルト処理を実行してくれます。

    先ほど紹介した4つのケースで、状況によってはretにnoErrが代入されないケースがひとつだけありあます。それは、アプリケーションメニューの「MOSAを終了」に準じたコマンドIDが’quit’のケースです。ここには「アプリケーションを終了させる」処理が記述されています。その本体が、以下のquitApplication()ルーチンです。

    short quitApplication(void)
    {
        WindowRef        wptr[MAX_BUF];
        unsigned long    i,ct;
        short            ret;
    
        ret=collectMyWindow( 'CATA',wptr,&ct );   // 開いているカタログウィンドウの
        for( i=0;i<ct;i++ )                        // すべてのWindowRefを配列へ集める
        {
            SelectWindow( wptr[i] );              // ひとつのウィンドウをフロントへ
            if( closeCatalogWindow( wptr[i],1 ) ) // ウィンドウを閉じるための処理
                return( 1 );                      // 閉じる処理はキャンセルされた
        }
        return( ret ); // retがゼロならアプリ終了、1ならば終了はキャンセル
    }
    


    お馴染みの「保存しますか?」アラートで「キャンセル」ボタンが押されて終了が中止されると、retにnoErrが代入されて処理がそこでストップします。この場合、アプリケーションは終了しません。逆に終了にOKサインが出た場合には、retはeventNotHandledErrのままなので、処理はStandard Handlerへと継承されます。そこでメインイベントループから抜けるためにQuitApplicationEventLoop()が呼ばれ、アプリケーションは完全に終了します。この部分を(Standard Handlerの力を借りないで)すべて自前で記述すると、以下の様になります。現状の処理と比較してみてください。

             case 'quit':
    
                  if( quitApplication()==0 )
                     QuitApplicationEventLoop();
                  ret=noErr;
                  break;
    


    今回は簡単な内容でしたが、Standard Handlerへ処理を継承させた方が効果的に目的を達せられる場合がある一例です。このテクニックを習得すると色々と便利に使えます。サッカーにおいて、パスをスルーする前に足でボールに触れ、方向やスピードをちょっと変化させる感じでしょうか?攻撃にバリエーションができます(笑)。旧ToolBoxのイベントシステムにはStandard Handlerのような便利な仕組みはなく、ありとあらゆるイベント処理を自分自身で記述する必要がありました。それと比較すると、Carbonアプリケーションの数多くの定型処理はStandard Handlerが受け持ってくれていますので、効率的に開発が行えるわけです。

    次回もイベントハンドラの4つのケースの処理について説明したいと思います。まずは、ウィンドウに実装するイベントハンドラの例題として、先に紹介したopenAboutWindow()の周辺を攻めてみたいと思います。

    つづく

    「Behind the WebObjects」  第25回  田畑 英和

     前回は、ERChangeNotificationJMS(以下ERCN)がどのようなときに役立つかを説明しましたが、今回はERCHのセットアップ方法を解説します。ERCNを使用する場合、別途OpenJMSのセットアップが必要になりますので、まずはそちらから紹介したいと思います。

    OpenJMSセットアップ

     まずOpenJMSの入手方法ですが、次のいずれかのURLからダウンロードしてください。今回は原稿執筆時点での最新バージョンのopenjms-0.7.6.1.tar.gzをダウンロードしてください。

    ・最新版ダウンロード
    http://openjms.sourceforge.net/downloads.html
    ・旧バージョン/ソースコードダウンロード
    http://sourceforge.net/project/showfiles.php?group_id=54559

     次にターミナル上でOpenJMSをダウンロードしたディレクトリに移動し、ダウンロードしたファイルを以下のコマンドで展開します。”openjms-0.7.6.1″という名前で展開されますが、この名前を”openjms”に変更してください。

    gzip -cd openjms-0.7.6.1.tar.gz | tar xvf -

     展開したファイルを”/usr/local”に移動します。Finderの「移動」メニューから「フォルダへ移動…」を選択し、”/usr/local”と入力してください。すると普段は不可視になっている”/usr/local”がFinder上に表示されますので、ここに展開した”openjms”フォルダをコピーします。
     コピー時には管理者の権限が必要になりパスワードの入力が求められますが、Panther以前のMac OSではFinder上でコピーすることができません。Panther以前のバージョンをお使いの場合はターミナル上でコピーをおこなってください。もちろんPantherでもターミナル上でコピーしてかまいません。

    ・OpenJMSのインストール先のパス
    /usr/local/openjms

     これでOpenJMSのインストールができましたので、次にOpenJMS起動のための前準備をおこないます。今回OpenJMSの起動はターミナル上でおこないますが、起動前に環境変数の設定が必要になりますので、ターミナル上で以下の2つのコマンドを実行してください。Pantherの場合はbashがデフォルトのシェルになっています。

    ・bashの場合
    export OPENJMS_HOME=/usr/local/openjms
    export JAVA_HOME=/usr/local/openjms
    ・tcshの場合
    setenv OPENJMS_HOME /usr/local/openjms
    setenv JAVA_HOME /Library/Java/Home

     あとProject WONDERのソース(Wonder-src-2.0.zip)にOpenJMS用の設定ファイルが含まれていますので、以下のとおりコピーします。

    ・コピー元ファイル
    Common/Frameworks/ERChangeNotificationJMS/Support/rmi_jms_jdbm.xml
    ・コピー先ディレクトリ
    /usr/local/openjms/config/

     さて、いよいよこれでOpenJMSを起動する準備が整いましたのでターミナル上で次のコマンドを入力し、OpenJMSを起動してください。ここではOpenJMSの起動スクリプト(startup.sh)があるディレクトリに移動し、設定ファイルを指定した状態でOpenJMSを起動しています。

    cd $OPENJMS_HOME/bin
    ./startup.sh -config ../config/rmi_jms_jdbm.xml &  

     OpenJMSを終了させるには以下のコマンドを入力してください。

    ./shutdown.sh -config ../config/rmi_jms_jdbm.xml

     OpenJMSのインストールやセットアップの詳細については次のURLに解説があります。

    http://openjms.sourceforge.net/gettingstarted.html

    ERChangeNotificationJMS.frameworkセットアップ

     ERCNのインストールですが、ビルド済みのProject WONDER(Wonder-2.0.zip)からERCNを以下のとおりコピーします。

    ・コピー元
    Frameworks/ERChangeNotificationJMS.framework
    ・コピー先ディレクトリ
    /Library/Frameworks

     この原稿を執筆している時点でのOpenJMSの最新版はVer 0.7.6.1になりますので今回は最新版に合わせて解説をおこなっていますが、Project WONDER2.0に含まれるERCHはOpenJMS 0.7.6を元にビルドされています。そこでまずERCHを最新版のOpenJMSに対応させます。

     ERCNはOpenJMSのライブラリを利用していますが、フレームワーク内にはあらかじめOpenJMS 0.7.6用のjarファイル存在していますので、まずはそれらのファイルを削除します。

    ・jarファイルのパス
    ERChangeNotificationJMS.framework/Resources/Java/
    ・削除するファイル
    jms_1.0.2a.jar, jndi_1.2.1.jar, openjms-client-0.7.6.jar

     OpenJMSを利用するのに必要なjarファイルですが、以下のURLにOpenJMSを使用するのに必要なjarファイルの一覧があり、ここで説明されているファイルは”/usr/local/openjms/lib/”にインストールされています。

    ・URL
    http://openjms.sourceforge.net/usersguide/jars.html
    ・必要なjarファイル
    openjms-client-0.7.6.1.jar, exolabcore-0.3.7.jar, jms-1.0.2a.jar,
    jndi-1.2.1.jar, commons-logging-1.0.3.jar

     この中にはERCNでは実際には使用されないファイルも含まれていますが、とりあえず5つのファイルをすべてERCNの”/Resources/Java/”にコピーします。これでこれでフレームワークの準備は完了です。

    ・コピー先ディレクトリ
    ERChangeNotificationJMS.framework/Resources/Java/

    アプリケーションのERCN対応

     まずERCN対応をおこなうプロジェクト開き、フレームワークグループにERCNフレームワークを追加します。
     次にプロジェクトのPropertiesファイル(存在しない場合は新規に作成してください)にERCNの設定を追加します。ERCNの設定は、Project WONDERのソースにサンプルが付属していますので、まずはこちらをコピーします。サンプルファイルは次のパスにある”SampleProperties.txt”です。

    ・ERCNサンプル設定ファイル
    Common/Frameworks/ERChangeNotificationJMS/Documentation/

     最後にプロジェクトをビルドします。これでERCNに対応したアプリケーションが作成されます。このときERCNに対応するからといってアプリケーションのソースコードはいっさい変更する必要はありません。ERCNフレームワークの追加をおこなえばあとは自動的に処理がおこなわれます。
     なお旧バージョンのERCNをすでに使用していた場合や、ERCNに含まれるjarファイルを入替えた場合は、アプリケーションのプロジェクトを再ビルドしてください。

    ERCNの動作確認ですが、まずアプリケーションのインスタンスを2つ起動して、両方のインスタンスでデータベース上の同一のデータをFetchし、EOを作成します。次に、片方のインスタンスだけでそのEOを変更してください。
     するともう片方のインスタンス上でも自動的にEOの変更内容が反映されていることが確認できます。これでインスタンス間でのEOの同期が実現できました。

    ニュース・解説

    今週の解説担当:新居雅行

    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    ┃Xcode 1.5がリリース
    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    Mac OS Xの開発ツールXcodeのVer.1.5がリリースされた。現在は、ADCサイトからADC会員のみしかダウンロードできないが、サイトの説明では今後のPantherにはXcode 1. 5がバンドルされるので、事実上機密情報ではなくなる事を考慮し、概要をお知らせしたい。
    Xcode 1.5の新しい機能としては、ビルドされたオブジェクトでの呼び出されていないコードの自動削除、リモートでバッグ、Javaでのキーワードなどの自動入力、Subversionのサポート、ネイティブビルドのlexやyaccそしてAppleScriptのサポート、Antのサポート、アプリケーションサーバ向けの開発機能の強化などとなっている。バグ修正やパフォーマンスの改善もされている。コンパイラのgccはVer.3.3となっている。

    Xcode
    http://developer.apple.com/tools/xcode/

    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    ┃FutureBasicの新バージョン「FutureBasic 4」がリリース
    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    Staz SoftwareはBASIC言語での開発ツール「FutureBasic 4」をリリースした。同社のサイトのリリース記録では、2002年にFutureBasic^3 Release 7を出して以来のバージョンアップとなる。動作環境はMac OS X 10.1以降あるいはMac OS 9.1以降となっており、Mac OS 9もサポートする。開発ツール自体をCarbonベースでかなりの部分を書き直し、エディタやプロジェクト管理機能が従来のバージョンより充実している。また、XMLベースでのIDEでのスクリプト機能をサポートするなど機能強化している。価格は$169。

    Staz Software
    http://www.stazsoftware.com/

    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    ┃Xcodeでのリモートデバッグの方法を解説した文書が公開
    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    Xcode 1.5でリモートデバッグがサポートされた。sshでネットワークした別のコンピュータ上で稼働するプログラムのデバッグが可能なので、たとえば全画面で実行しているプログラムのデバッグもXcodeでできるということになる。sshのキー生成、Xcodeでの基本的な設定方法がまとめられている。

    Introduction to Remote Debugging With Xcode
    http://developer.apple.com/documentation/DeveloperTools/Conceptual/RemoteDebugging/

    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    ┃Xcodeを使ったソース管理の手法を解説した文書が公開
    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    XcodeでのSCM(Source Control Management)についての文書が公開された。
    CVS、Subversion、Perfoceについての手法が記載されている。いずれも、ソースのインポート自体はコマンドを使って行うが、その後はXcodeでの機能を使えばいいとなっている。なお、nibファイルやバンドルなどについてはCVSではcvswrappersというファイルをインストールする事で、ロックをかけることができることなどが解説されている。CVSではバンドルやファイルパッケージに対して複数のデベロッパが編集をかけないようにする仕組みがあるが、SubvertionやPerfoceでは利用できない。

    Introduction to Xcode Source Control Management
    http://developer.apple.com/documentation/DeveloperTools/Conceptual/Xcode_SCM/index.html

    MOSAからのお知らせと編集後記は割愛します

    MOSA Developer News   略称[MOSADeN=モサ伝]
    Apple、Mac OSは米国アップルコンピュータ社の登録商標です。またそのほかの各製品名等はそれぞれ各社の商標ならびに登録商標です。
    このメールの再配信、および掲載された記事の無断転載を禁じます。
    http://www.mosa.gr.jp/
    Copyright (C)2004-2006 MOSA. All rights reserved.

  • MOSA Developer News[MOSADeN=モサ伝]第123号

    2004-08-03

    目次

    • SqueakではじめるSmalltalk入門   第5回  鷲見正人
    • 藤本裕之のプログラミング夜話 #50
    • 高橋真人の「プログラミング指南」 第49回
    • ニュース・解説

    SqueakではじめるSmalltalk入門   第5回  鷲見正人

     本連載では、名前はよく耳にしていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。今回は前回提示した短いペイントスクリプトの内容に順を追って解説を加えます。

    前回のプログラムは次のようなものでした。便宜的に、行頭にはコメントのかたちで行番号を振ってあります。

    "01" | pen |
    "02" pen _ Pen new.
    "03" pen defaultNib: 3.
    "04" pen color: Color red.
    "05" [Sensor shiftPressed] whileFalse: [
    "06"    | position |
    "07"    position _ Sensor peekPosition.
    "08"    Sensor redButtonPressed
    "09"       ifTrue: [pen goto: position]
    "10"       ifFalse: [pen place: position]]

     Smalltalkのプログラムコードは、目が慣れてしまえば、自然言語(英語)の文章を読むように、比較的容易にその内容を理解できるのがその特徴です。もちろん、変数名やメソッド名(セレクタ)を考える際に、それを使って書いたコードが、平易で読み下し易いものになるよう心がけることが推奨されており、ユーザー(プログラマ)がそれを遵守することが前提です。結果、変数名やメソッド名は長くなりがちですが、組み込みエディタの簡易補完やコンパイラのスペル修正機能のサポートが期待できるので、初期のProject Builderにおける、Objective-C/CocoaプログラミングやAppleScriptプログラミングのときのようなストレスを心配する必要はないでしょう。

    1行目は、一時変数「pen」の宣言です。ちなみに、複数の一時変数を宣言したいときは、スペースで区切って列挙します。FORTRANやALGOLの流れを汲む言語でよく見られる「,」(コンマ)を区切り記号に使わないのは、Smalltalkが前二者よりLISPからの影響を強く受けているからだと思います。余談ですが、コンマは「コレクション」と呼ばれる配列の仲間(文字列を含む)のオブジェクト同士を連結するときに用いる二項セレクタ(関数名)として登録されているので、項目列挙の際に区切りのつもりでうっかり使うとエラーになったり、思わぬ結果が生じることもあるので気を付けてください。

    #(1 2 3 4), #(5 6 7) “=> #(1 2 3 4 5 6 7) 配列の結合 ”
    ‘This is a ‘, ‘pen.’ “=> ‘This is a pen.’ 文字列の結合 ”

     話を戻して、2行目は宣言した一時変数「pen」に、クラス「Pen」のインスタンスを束縛(代入)しています。Smalltalkの変数は型を持たないため、中にデータを入れる“箱”というよりは、本来無名のオブジェクトに付ける“名前”になぞらえたほうがしっくりきます。また、ここで「代入」や「命名」ではなく「束縛」という言い回しをするのは、変数への束縛が、単に名前を付けるというだけでなく、オブジェクトの寿命を決定づける意味合いも持つからです。仮に「Pen new」を評価してオブジェクトを生じさせても、そのまま放っておけばガベージコレクタに瞬殺されてしまいます。誕生させたオブジェクトを確保し、続く式でメッセージを送って何らかの振る舞いをさせるための参照と延命のための作業が、変数への“束縛”、というわけです。

    前後しますが「Pen new」は、クラス「Pen」にメッセージ「new」を送信してオブジェクトを生成するための式です。クラスはオブジェクトの設計図と言うべき存在で、そのクラスに属するオブジェクト(インスタンス)が内部にいくつのメモリ(インスタンス変数)を持ち、どんなメッセージに応答でき(セレクタ)そのときどんな振る舞いをするか(メソッド)を定義します。システムは、クラスの定義記述に従ってオブジェクトを生みだし、しかるべく振る舞わせます。

    Smalltalkでは、クラスもまたオブジェクト(クラスのクラスの唯一のインスタンス)なので、メッセージを受けることができ、それに相応しい決められた振る舞いをします。メッセージ「new」は、そのクラスに属するインスタンス(オブジェクト)を生成するために送る一般的なメッセージです。クラス「Pen」は有名な、しかしSmalltalkが発祥だとは意外と知られていない「BitBlt」(bit block transfer)クラスのサブクラスで、LOGOの“タートル”のような振る舞いをするオブジェクトを定義します。

    二つ以上の式を区切って区別するには「.」(ピリオド)を用います。これは終端記号ではないので、最終行には付ける必要はありません(あってもエラーにはなりません)。改行や余計なスペース、タブは式の解釈には影響を与えないので、主に可読性向上を目指した整形のために用います。

     3行目と4行目では一時変数「pen」に束縛した、Penのインスタンスに対してメッセージを送ることで、その“状態”を変化させています。3行目で送っているメッセージ「defautlNib: 3」はペン先(nib)の太さを3ドットに変更するためのもので、4行目の「color: Color red」はペンの色を赤に変えるためのものです。念のためおさらいしておくと、前者のセレクタは「#defaultNib:」パラメータは「3」、後者のセレクタは「#color:」パラメータは式「Color red」の返値となります。式「Color red」自体もメッセージ式で、クラス「Color」に「red」というメッセージを送りColorに属する“赤い色”というオブジェクトを生じさせています。同様に、「Color blue」とすれば“青い色”、「Color green」とすれば“緑色”を指定できます。

    これでペン「pen」の準備ができたので、あとはマウスの動きにpenの動きを、マウスボタン操作にpenの上げ下げ連動させればお手軽ペイントソフトを機能させることができます。この部分を記述したのが5行目以降です。

    次回は、ループやif-then-elseといった条件分岐を、通常のプログラミング言語がするような「構文」ではなく、どのようにして「式」で表現しているのかを解説します。

    サポートページ:
    http://squab.no-ip.com:8080/mosaren/

    藤本裕之のプログラミング夜話 #50

     突然思い出したが、WWDCに行ったサンフランシスコでいきなりタカハシさんに「フジモトさん、OOP入門はどうなったんですか」と訊かれたのだった。「え、あれで終わりだけど」と答えると、チッチッと言う感じで指を振り「全然終わってないですよ」と。
     いやあのその別にC++とかObjective-Cの教科書みたいに網羅的にやるつもりは最初からなくて、あの最中にも書いたと思うけれどもオブジェクト指向プログラミングの、なんつうか取っ付きの悪い概念とか仕組みについて地に足がついたコトバで解説してみたかっただけなのでその、オレとしては当初の目論見は達したというかしどろもどろ、と言い訳をしたんだが、「でも例えば多重継承とかは……」とタカハシさんは追及するのだった。
     はい、その通り。継承についてはしつこく説明したけれども多重継承については一言も書いてない。何故ってねぇ、オレはキライなのだあの「多重継承」というヤツが。「キライったってお前、そういうもんぢゃないだろう」と口をトンガラかすキミの顔が目に浮かぶ……わけもないが、とにかくそういうことなので、今回は、オレがなんでコイツを嫌うか、という理由を通して多重継承についての説明を試みたいと思う。

    まず基本的なコトなんだけど、多重継承というのはつまり、あるクラスが互いに継承関係のない複数のスーパークラスを持っている状態のことである。C++では例えば以下のように書く。

    class Animal { ... };
    class Bird { ... };
    class Bat : public Animal, public Bird { ... };
    

     上の場合、BatというクラスはAnimalおよびBirdをスーパークラスとして持つ。両方ともpublicであるから(難しい言葉では「公開派生」とか言う)、Animalの持つメソッドもBird固有のメソッドもBatに対してコールすることができる……。
     便利ぢゃないかって? サイテーである(いや、個人的見解だからね)。
     オレが気に入らないのは、これが文字通り「コーモリはケモノである,でも空を飛ばなくちゃヘンだからトリでもある」ということを可能にしてしまう仕組みだからである。つまり「現実世界を模式化することでプログラムの構造を簡潔にできる」ことがウリのオブジェクト指向の理念に反して、この機構は「現実世界にはあり得ないモノを作り出してしまえる」のだ。なにが問題か分からない? 有り体に言えばこの多重継承という機構には「設計をちゃんとできないプログラマの味方」という側面があるのだよ。
     よくできたオブジェクト指向のプログラムはパーツパーツが独立していながら総体として一つのシステムを為している。前にも書いたと思うが、我々が意識しなくても心筋は脈動し全身に血液を行き渡らせるし、ランゲルハンス島は血糖値に応じてインシュリンを分泌するわけだ。ところがそういううまい設計をしなくてもなんとかなってしまうヤリカタがある。心筋からランゲルハンス島まで全ての機能をサブクラスして1つのクラスを作るのだ。
     言ってること、わかるでしょ? 多重継承というのは使いようひとつでオブジェクト指向をオブジェクト指向でなくしてしまうことのできる(そしてヘタなプログラマはそういう風に使いがちな)困った機構なのである。

    正直に言うとオレ自身,かつてC++で書いたプログラムの中に「苦し紛れにやった多重継承」が散見できる。もちろん言い訳はあって、最初からそんなヌエみたいなオブジェクトがゴロゴロあったわけではなく、バージョンアップとかのときにオブジェクト相互の関係をできるだけ壊さないで(つまり構造を変えないで)、要求されている新機能を加えようとしてそうなっちゃったんだが、それを見るたび全部書き直したくて胃が焼けるような思いだった(今はもう多重継承のできないObjective-Cで書き直したので胃は痛くない)。
     と、こういうわけでワタシは多重継承がキライなんであり、多重継承というのはそういうものなんであった。わかっていただけたであろうか。わかんないか。
    (2004_07_30)

    高橋真人の「プログラミング指南」第49回

    オブジェクト指向のとっかかり(34)

    〜Macにおけるオブジェクト指向(続)〜

     こんにちは、高橋真人です。さっそく続きです。
     Core Foundationで最も使われるのはCFStringでしょう。これは文字列のための仕組みで、単なる文字の配列で作られるCの文字列とは違って、いくらかの応用力を持っています。
     たとえば従来のMac OSにおいて文字コードの変換に使われていたText Encoding Converterですが、Core Foundationの文字列関係の機能を使うことで直接呼び出す必要がなくなります。
     具体的な例として、Shift JISで作られたファイルをEUCに書き出すというケースを考えてみます。
     最初に読み込みデータを「これはShift JISのデータである」と指定してCFStringに読み込ませます。CFStringは内部ではデータをUnicodeで保持することになっているので、従来Shift JISの処理に付きものだった「上位バイト、下位バイト」といったことにもわずらわされずに文字列処理をすることができます。
     処理が終わって書き出す段になったら「EUCのデータとして書き出せ」と指示してやればよいというわけです。
     さて、CFStringを使って文字列の処理をする場合、文字列の比較はどうするかということで、比較関数を探してみます。

    http://developer.apple.com/documentation/CoreFoundation/Reference/CFStringRef/Reference/FunctionGroupIndex.html

    を見てみますと、CFStringCompare()というAPIがあることが分かります。以下のような感じで使います。

    CFStringRef str1, str2;
    str1 = CFSTR("0123");
    str2 = CFStringCreateWithFormat(NULL, NULL, CFSTR("%04d"), 123);
    
    if (CFStringCompare(str1, str2, 0) == 0) {
        CFShow(CFSTR("Same"));
    }
    else {
        CFShow(CFSTR("Not same"));
    }
    


     ちょっとごちゃごちゃしている部分があるので、読みにくいかもしれませんが、CFStringCreateWithFormat()というのは、ANSI Cでいうところのprintf()方式で新たにCFStringの文字列を生成するAPIです。従って、str1とstr2には結果的に同じ文字列が格納されることになるので、比較の結果は「同じ」となるわけです。
     ところで、CFStringに極めて似た役割を持ち、文字列の代わりにバイト列を保持するCFDataというのがあります。

    http://developer.apple.com/documentation/CoreFoundation/Reference/CFDataRef/Reference/FunctionGroupIndex.html

    にAPIの一覧がありますが、CFStringに比べると極端に数が少ないですね。
     バイト列として保持しているデータを比較したいというケースも、文字列ほどではないにしても当然あるわけですが、その場合どうしたらよいのでしょう?
     「バイトデータを一つずつ取り出して、順番に比較する」? まさかね(笑)。
     実は、CFDataRefで保持しているバイト列同士を比較する場合、CFEqual()というAPIが使えます。ん? 「そんなもの、さっきのところにはなかった」って?
     確かにその通り。では、CFEqual()なんてAPIはどこにあるのでしょう?
     ここにあります。

    http://developer.apple.com/documentation/CoreFoundation/Reference/CFTypeRef/Reference/FunctionGroupIndex.html#//apple_ref/c/func/CFEqual

     あれ、このAPI、引数として取るのはCFTypeRefってなってますね。これはいったい何なのでしょう?
     前回の時にちょっと触れたのですが、覚えているでしょうか?

     Derived From: CFPropertyList : CFType

     こんなやつです。
     実は、ここのCFTypeってのがまさにそれなんです。CFDataはCFPropertyListというのを経由して、CFTypeから派生していることになっていますから、CFTypeとしての性質も併せ持っているために、CFEqual()に引数として与えることができるって具合なんです。
     そうだとすれば、考えればお分かりの通り、同じ理屈でCFStringに関しても、CFEqual()を使って比較ができることになります。これを用いれば、ANSI Cのstrcmp()のように「== 0」と、ゼロと比較することで「文字列が同じである」と表すのよりももっと直接的な表現になりますね。

    if (CFEqual(str1, str2)) {

     どうでしょうか? 確かに言語がCなので、関数のオーバーライドなどというようなことはできないものの、まさしくポリモーフィズムを実現していると思いませんか?

    ニュース・解説

    今週の解説担当:小池邦人

    Carbon ドキュメント & サンプル & SDK ナビゲーション(2004/07/30)

    【開発環境】

    株式会社ヒューリンクスが、Xcode上で使用可能なIBMのXL C/C++コンパイラの販売を開始しました。これにより、Mac OS X開発環境としてもうひとつの選択肢が提供されることになったわけで、デベロッパーにとっては大変喜ばしいことです。なにせPowerPCを設計しているIBMのC/C++コンパイラですから、その信頼性の高さについては疑問の余地がないでしょう(長年自社内で使用しているでしょうし)。実は、WWDC2004においても、64ビットコンピューティングのセッションでIBMの技術社がゲストスピーカーとして壇上に上り、このコンパイラについての詳しい解説を行いました。

    価格は「IBM XL C/C++ Absoft Fx デバッガ MacOSX」で 107,100です。教育用(学割のこと?)として購入する場合には、ほぼ半額の 58,800です。う〜ん、落ち着いたらどこかの大学の先生か学生になりたいところです(笑)。

    http://www.hulinks.co.jp/software/xlc_mac/

    【テクニカルドキュメント】

    前回から7月30日の期間中、Apple社のDocumentationサイトにはドキュメントがひとつも登録されませんでしたが、デベロッパ向けの読み物として以下の2つの解説が登録されています。

    「Simultaneous Development: Blizzard Does Both At Once」(読み物)

    http://developer.apple.com/business/macmarket/blizzard.html

    「Installing the W3C HTML Validator on Mac OS X」(読み物)

    http://developer.apple.com/internet/opensource/validator.html

    前回から7月30日の期間中、新規のテクニカルノートはひとつも登録されませんでした。テクニカルQ&Aの方は3つ登録されました。Rendezvous関連の解説です。Rendezvousは商標の関係により、その名称がOpenTalkに変更されると言う噂があります。さてどうなんでしょうか? 個人的意見としては、OpenTalkの方が分かりやすくて良いと思うのですが(笑)。

    QA1306「Rendezvous enforces the TXT record format in Panther」
    QA1312「Rendezvous service types used in Mac OS X」
    QA1302「Updating the TXT record of a Rendezvous service」

    http://developer.apple.com/technicalqas/index-rev-date.html

    【サンプルソースコード】

    前回から7月30日の期間中、Apple社のSample Codeサイトには、新しいサンプルソースコードが2つ登録されました。両方とも新しいバージョンとしての再録です。

    「AppleJavaExtensions 」(Java関連)
    「SimplePlayThru」(Core Audio関連)

    http://developer.apple.com/samplecode/index-rev-date.html

    【デベロップメント SDK】

    前回から7月30日の期間中、Apple社のSDKサイトには新しいSDKはひとつも登録されませんでした。

    http://developer.apple.com/sdk/

    MOSAからのお知らせと編集後記は割愛します

    MOSA Developer News   略称[MOSADeN=モサ伝]
    Apple、Mac OSは米国アップルコンピュータ社の登録商標です。またそのほかの各製品名等はそれぞれ各社の商標ならびに登録商標です。
    このメールの再配信、および掲載された記事の無断転載を禁じます。
    http://www.mosa.gr.jp/
    Copyright (C)2004-2006 MOSA. All rights reserved.