MOSA Multi-OS Software Artists

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

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

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

MOSADenバックナンバー 2005年3月発行分

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

    2005-03-29

    目次

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

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

     本連載では、名前は知っていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。コレクションの抽象クラス「Collection」のプロトコルを覗きながら、コレクションがどんなメッセージを受け付けるオブジェクトなのか、その“正体”を探っているところなのですが、ちょっと寄り道して、コレクションに対する二項演算がどのように実現されているのかを見ています。

     前回は、数値を引数にとる場合の解説をしました。たとえば#(1 2 3)に「* 4」というメッセージを送信している式なら、Collection >> #*から、Number >> #adaptToCollection:andSend:が呼び出され、そこでの定義から元の式が、

    #(1 2 3) collect: [:element | element * 4]

    と解釈可能となり、結果、各要素に「* 4」を送信して得られた結果を要素とする新しいコレクション#(4 8 12)が返ってくる…という流れでした。

     そして課題は、パラメータが4ではなく#(4 5 6)のとき、どんなカスケードが起こるのか…、もう少しうがった事を言うと、case-switchのような条件分岐を使わずにパラメータの違いによる振る舞いを変更するためにどうしているのか?でしたね。では、早速。

     とりあえず#(1 2 3)は、送られるメッセージが「* 4」であろうと「* #(4 5 6)」であろうと、セレクタが「#*」である限り、同じメソッドCollection >>#*を起動します。

    Collection >> * arg
       ^ arg adaptToCollection: self andSend: #*

     まったく同じメソッドの起動ですから、この時点ではまだ多態はしていません。

     前回、引数argには、NumberのサブクラスであるSmallIntegerに属する4が束縛されていましたが、今回はCollectionのサブクラスであるArrayに属する#(4 5 6)を束縛しています。argに送るメッセージは同じですが、argに束縛されているオブジェクトが異なるので、起動するメソッドも、4のときのNumber >>#adaptToCollection:andSend:とは別のものになります。

     ここでようやく振る舞いに変化が生じます。引数argに改めてメッセージを送っているのがミソですね。なお、このようにレシーバだけではなく、引数についてもこれに依存的な多態を実現するための機構を、一般に「ダブルディスパッチ」と呼びます。

     Arrayとそのスーパークラス群にはCollectionに至るまで#adaptToCollection:andSend:は定義されていないので、結局、argに束縛された#(4 5 6)は、Collection >> #adaptToCollection:andSend:を起動します。

    Collection >> adaptToCollection: rcvr andSend: selector
       rcvr isSequenceable & self isSequenceable ifFalse:
          [self error: 'Only sequenceable collections may be combined arithmetically'].
       ^ rcvr with: self collect:
          [:rcvrElement :myElement |
             rcvrElement perform: selector with: myElement]

     最初の式は、レシーバ、引数のいずれかが要素の順番を扱うことができないコレクションならエラーを生じさせるためのフェールセーフです。とりあえずこれは無視して第二式目に集中しましょう。「* 4」のときと同様に、self、rcvr、selector、それぞれに実際に束縛されているオブジェクトを割り当てて、より分かりやすい式に書き換えてみると次のようになります。ブロック変数名も短くしてみました。

    #(1 2 3) with: #(4 5 6) collect: [:a :b | a perform: #* with: b]

     さらに、#perform:with:も、第一引数のセレクタが確定していれば、等価なメッセージ式に置き換えることができましたよね。結果、#(1 2 3) * #(4 5 6)は、次のように解釈されると考えてよさそうです。

    #(1 2 3) with: #(4 5 6) collect: [:a :b | a * b] ” => #(4 10 18) ”

     #with:collect:は初出ですが、#collect:と見た目が似ているので動作の予想は容易いと思います。ブロックを評価した結果を集めて(collect=コレクト…して)返す点では同じです。ただ、#collect:はレシーバの各要素を評価に用いるのに対し、#with:collect:は第二引数のコレクションの同じ順番の要素も一緒に用います。詳しくは#with:collect:の定義をご覧ください。#with:collect:の定義は、ブラウザ中段のimplementorsボタンを押したときに現われるポップアップから「with:collect:」を選んで呼び出すのが早いでしょう。

     さて。前回から引き続き、以上駆け足でしたが、#(1 2 3)に「* #(4 5 6)」というメッセージを送信したとき、対応する各要素の積を要素とする配列#(4 10 18)が返ってくるしくみ、ひいては「* 4」を送信したときと振る舞いを変えることがどうして可能なのかについての理解を深めていただくことができたかと思います。case-swithという手続き的な記述で済ますのではなく、あくまでオブジェクトにメッセージを送って、その適切な振る舞いに期待する…というスタイルは、まさに(ケイの)「オブジェクト指向」の面目躍如といったところでしょうか。また、実際にシステム内で運用されている、こうしたカラクリのかなりの部分がSmalltalk自身で記述されており、いつでも気軽に簡単にそのソースに当たることができる…という点も、Smalltalkシステムならではの特徴と言えそうです。

    バックナンバー:
    http://squab.no-ip.com:8080/mosaren/

    小池邦人の「Carbon API 徒然草」(2005/03/25)

    Navigation Service APIの活用(その7)

    今回は「Navigation Service APIの活用」の最終回です。FSSpecの代わりにFSRefを得るために有用なシートウィンドウ版の「フォルダ選択ダイアログ」と「ファイル名選択ダイアログ」を紹介したいと思います。

    まず最初に、フォルダ選択用のシートウィンドウを表示するnavChooseFolderSheet()ルーチンを紹介します。使用方法は以前(その3)で解説したnavPutFileSheet()ルーチンとほとんど同じですので、そちらを参照してください。前回と少し異なるのは、フォルダ選択時に親ウィンドウが存在しないと(window==NULLの場合)シートウィンドウではなく、通常のモーダルダイアログとしてオープンするように設定されている箇所です。フォルダが選択された後の実際の処理は、NavCreateChooseFolderDialog()に引数として渡されるイベント処理ルーチンのnavGetEventSheeProc()の方に記述します。

    #define   MY_SIG   'MosA'   // アプリケーションのシグネイチャ
    
    short navChooseFolderSheet( WindowRef window )
    {
        short                       ret=1;
        NavDialogRef                dptr;
        Str255                      str;
        NavDialogCreationOptions    opt;
    
        if( ! NavGetDefaultDialogCreationOptions( &opt ) ) // オプションを初期化
        {
            if( window ) // 親ウィンドウがあるのでシートウィンドウとして表示
            {
                opt.parentWindow=window;                  // 親ウィンドウを代入
                opt.modality=kWindowModalityWindowModal;  // シートと設定
            }
            else        // 親ウィンドウが無いのでモーダルダイアログとして表示
                opt.modality=kWindowModalityNone;         //  ダイアログと設定
            opt.preferenceKey=MY_SIG;                     // 使用形態の識別値を設定
            opt.optionFlags+=kNavNoTypePopup;     // 種類ポップアップメニュー未使用
            GetIndString( str,128,1 );
            opt.clientName=CFStringCreateWithPascalString( NULL,str,
                                                   CFStringGetSystemEncoding() ) );
                                               // クライアント名をリソースから設定
            GetIndString( str,128,2 );
            opt.message=CFStringCreateWithPascalString( NULL,str,
                                                   CFStringGetSystemEncoding() ) );
                                               // メッセージ文字をリソースから設定
            if( ! NavCreateChooseFolderDialog( &opt,navGetEventSheeProc,NULL,
                                                          (void *)window,&dptr ) )
                                                // シートウィンドウを作成する
            {
                if( ret=NavDialogRun( dptr ) )  // シートウィンドウを表示する
                    NavDialogDispose( dptr );
            }
            if( opt.message )
                CFRelease( opt.message );     // メッセージ文字をリリース
            if( opt.clientName )
                CFRelease( opt.clientName );  // クライアント名をリリース
        }
        return( ret );
    }
    


    次は、ファイル選択用のシートウィンドウを表示するためのnavGetFileSheet()ルーチンです。navChooseFolderSheet()と異なるのは、前回紹介したnavMakeTypeList()で、選択対象ファイルタイプをNavTypeListHandleに変換してから渡している箇所です。ただし、今回は拡張子によるファイルタイプの判断はしていませんので、実際にこのルーチンを用いる場合には、前回と同様にフィルタルーチンによる判断が必要な場合もあります。注意してください。

    short navGetFileSheet( WindowRef window,OSType type )
    {
        short                       ret=1;
        NavDialogRef                dptr;
        NavTypeListHandle           list;
        NavDialogCreationOptions    opt;
    
        if( ! navMakeTypeList( 1,&type,&list ); // ファイルタイプリストを作成
        {
            if( ! NavGetDefaultDialogCreationOptions( &opt ) ) // オプションを初期化
            {
                if( window ) // 親ウィンドウがあるのでシートウィンドウとして表示
                {
                    opt.parentWindow=window;                  // 親ウィンドウを代入
                    opt.modality=kWindowModalityWindowModal;  // シートと設定
                }
                else       // 親ウィンドウが無いのでモーダルダイアログとして表示
                    opt.modality=kWindowModalityNone;        //  ダイアログと設定
                opt.preferenceKey=MY_SIG;          // 使用形態の識別値を設定
                opt.optionFlags+=kNavNoTypePopup;  // 種類ポップアップメニュー未使用
                GetIndString( str,128,1 );
                   opt.clientName=CFStringCreateWithPascalString( NULL,str,
                                                   CFStringGetSystemEncoding() ) );
                                               // クライアント名をリソースから設定
                GetIndString( str,128,3 );
                opt.message=CFStringCreateWithPascalString( NULL,str,
                                                   CFStringGetSystemEncoding() ) );
                                               // メッセージ文字をリソースから設定
                if( ! NavCreateGetFileDialog( &opt,list,navGetEventSheeProc,NULL,
                                                     NULL,(void *)window,&dptr ) )
                                               // シートウィンドウを作成する
                {
                    if( ret=NavDialogRun( dptr ) ) // シートウィンドウを表示する
                        NavDialogDispose( dptr );
                }
                if( opt.message )
                    CFRelease( opt.message );      // メッセージ文字をリリース
                if( opt.clientName )
                    CFRelease( opt.clientName );   // クライアント名をリリース
            }
            DisposeHandle( (Handle)list );
        }
        return( ret );
    }
    


    両シートウィンドウにおけるユーザ操作(ボタンクリック等)に対応するための処理は、NavCreateChooseFolderDialog()とNavCreateGetFileDialog()に引数として渡されているnavGetEventSheeProc()(イベント処理ルーチン)の方に記述します。フォルダやファイルが選択され、ウィンドウ上の「選択」や「開く」ボタンが押されると、このルーチンが呼ばれることになります。ユーザの操作内容は、引数で渡されるNavCBRecPtr経由で判断することが出来ます。今回は、どちらのボタンクリックでもnavGetEventSheeProc()ルーチンが呼ばれていることが理解できます。

    pascal void navGetEventSheeProc( NavEventCallbackMessage sel,
                                          NavCBRecPtr parm,NavCallBackUserData ud )
    {
        NavReplyRecord   reply;
        DescType         rtype;
        FSRef            fsref;
        WindowRef        wptr;
        Size             len;
        AEKeyword        key;
        FSSpec           fsc;
    
        if( parm->context )
        {
            wptr=(WidnowRef)ud;  // 親ウィンドウのWindowRefを得る
            switch( sel )
            {
                case kNavCBUserAction:  // ユーザが何どんな操作を実行したか?
    
                    switch( parm->userAction )
                    {
                        case kNavUserActionChoose: // 選択ボタンが押された
    
                            navGetEventSheeProc( wptr,0,&reply ); // フォルダ処理
                            NavDisposeReply( &reply ); // NavReplyRecord構造体破棄
                            break;
    
                        case kNavUserActionOpen:  // 開くボタンが押された
    
                            navGetEventSheeProc( wptr,1,&reply ); // ファイル処理
                            NavDisposeReply( &reply ); // NavReplyRecord構造体破棄
                            break;
                    }
                    break;
    
                case kNavCBTerminate:
    
                    NavDialogDispose( parm->context ); //シートウィンドウを削除
                    break;
            }
        }
    }
    


    getFilesInfo()ルーチンがどちらの処理から呼ばれたのかは、引数のkindがゼロか1かで判断できます。最初にAEGetNthPtr()を使い、選択された個数分だけフォルダやファイルのFSRefを得ます。その後、FSGetCatalogInfo()によりFSRefをFSSpecへ変換し、同時にFSpGetFInfo()によりファイルタイプを得て、それ以降の処理に渡すための情報を準備しています。しかし、こうした処理はアプリケーション側の処理内容によっては不必要な場合もあるでしょう。

    short getFilesInfo( WindowRef window,long kind,NavReplyRecord *reply )
    {
        long         i,ct=0;
        DescType     rtype;
        FSRef        fsref;
        short        ret=1;
        OSType       type;
        FSSpec       fsc;
        Size         len;
        AEKeyword    key;
        FInfo        ff;
        long         ct;
    
        AECountItems( &reply->selection,&ct ); // 幾つオブジェクトが選択されたか?
        if( ct )
        {
            for( i=1;i<=ct;i++ )              // 選択された個数分だけループする
            {
                if( ! AEGetNthPtr( &reply->selection,i,typeFSRef,&key,&rtype,
                                               (Ptr)&fsref,sizeof( FSRef ),&len ) )
                                              // 選択オブジェクトのFSRefを得る
                {
                    FSGetCatalogInfo( &fsref,kFSCatInfoGettableInfo,NULL,NULL,
                                                                      &fsc,NULL );
                                              // FSRefからFSSPecを得る
                    FSpGetFInfo( &fsc,&ff );  // Finder情報を得る
                    type=ff.fdType;           // ファイルタイプを抽出
    
                    if( kind==0 ) // ここにフォルダ選択用の処理を記述する
                    {
                    }
                    else          // こちらにはファイル選択用の処理を記述する
                    {
                    }
                }
            }
            ret=noErr;
        }
        return( ret );
    }
    


    今回で「Navigation Service API」の話は終了です。次回は、Macintoshの「もうひとつのファイル読み込み方法」である、Finderからアプリケーションへのアイコン(フォルダやファイル)のDrag&Dropについて解説したいと思います。

    つづく

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

     運用の解説の3回目ですが、前回Monitorの設定までおこないましたので、今回はいよいよアプリケーションを登録して運用を開始する方法を説明したいと思います。

    アプリケーションの登録

     Monitorを起動すると最初に「Applications」画面が表示(パスワードを設定している場合はパスワードの入力が必要)されますが、ここでアプリケーションの登録をおこないます。すでにアプリケーションを登録している場合は、この画面に登録済みのアプリケーション一覧が表示されます。
     アプリケーション名を入力するテキストフィールドが画面の下にありますので、こちらにアプリケーション名を入力して「Add Application」ボタンをクリックします。するとアプリケーションの設定画面に移動しますので、ここでこれから運用をおこなうアプリケーションの様々なパラメータを入力していきます。
     入力項目は色々あるのですがまずはPathの入力をおこなってください。ここにはアプリケーションの起動スクリプトのパスを入力します。起動スクリプトのパスですが、”MyApp”という名前のプロジェクトをインストールした場合、起動スクリプトのパスは以下のとおりになります。

    ・起動スクリプトのパス(Mac OS X用)
    /Library/WebObjects/Applications/MyApp.woa/MyApp

     インストール先は自由に変更することができますが、特に指定しなかった場合はこのようなパスになります。このパスをMonitor上で登録するわけですが、Pathの入力フィールドはプラットフォームごとに分かれていますので、適切なフィールドにパスを設定してください。パスは直接入力することもできますが、Monitorの「Path Wizard」機能を利用して画面上でパスを指定することもできます。

    起動の確認

     最低限パスの設定をおこなえばアプリケーションを起動することができますが、まずは運用環境でアプリケーションが正常に起動するかを確認しておきましょう。設定ミスのためにアプリケーションを正常に起動できない場合も考えられます。
     起動の確認をするにはターミナル上で起動スクリプトを実行してみてください。設定が正しくおこなわれている場合はこれでアプリケーションが起動します。開発環境ではアプリケーションの起動時に自動的にWebブラウザが起動してアプリケーションにアクセスしますが、運用環境ではこれを手動でおこなう必要があります。
     もしアプリケーションが正常に起動しない場合は、アプリケーションが利用しているフレームワーク/ライブラリが運用環境にインストールされているかや、モデル上でデータベースの接続情報が正しく設定されているかを確認してください。開発環境と運用環境でデータベースを使い分けている場合、データベースの接続情報の書き換えが必要になります。

    起動の確認

     さて、起動の確認ができましたらいよいよ運用の開始です。パスを設定したアプリケーションの設定画面の右上に「Detail View」ボタンがありますのでこちらをクリックしてインスタンスの一覧画面に移動します。WebObjectsでは同じアプリケーションを複数同時に起動することができますが、起動した個々のアプリケーションのことをインスタンスと呼んでいます。
     画面の下に追加するインスタンスの数を入力するフィールドがありますのでまずはインスタンス数1で「Add」ボタンをクリックしてください。するとインスタンスが1つ追加されて、デフォルトの設定ではそのまま自動起動するようになっています。しばらくするとStatusがONになりインスタンスの起動が確認できます。いつまでもStatusがOFFのままの場合はどこかで設定が間違えているはずですので、もう一度最初から設定を確認してみてください。
     また、本格的な運用をおこなう前にまずは単純なサンプルアプリケーションを作成してそちらで運用のリハーサルをおこなうのもよいでしょう。

    複数インスタンスの起動

     WebObjectsの運用環境は標準で負荷分散に対応しており、1台のアプリケーションサーバ上でインスタンスを複数起動することができます。もっともメモリなどサーバのリソースには限りがありますので、ある程度の規模になるとアプリケーションサーバを追加してシステムのスケーラビリティを上げることもできます。
     インスタンスを複数起動するのはMonitor上で簡単にできるのですがこのとき注意しなければならないことがあります。それはインスタンス間でのデータの同期です。EOFはデータベースから取得したデータをキャッシュしますのであるインスタンスでデータが変更されても、別のインスタンス上では古いデータを保持したままの状態であることが考えられます。また他のアプリケーションから同一のデータベースを更新したときにも同様の問題が発生します。
     このようなインスタンス間でのデータの不整合を防ぐには、アプリケーションを開発する時点でキャッシュを考慮した設計をおこなっておく必要があります。WebObjectsにはキャッシュを回避してデータをリフレッシュするAPIも用意されています。以前この連載で自動的にインスタンス間でのデータの同期をおこなうProject WONDERのChangeNotification JMSを紹介しましたが、残念ながら場合によっては動作に問題があるようです。
     他のインスタンス(あるいはアプリケーション)によって更新される可能性のあるデータは、毎回直接データベースを参照するなどして明示的にデータのリフレッシュをおこなう必要があります。

    The End

     さてこの連載ですが実は今回で一区切りとさせていただいて、次回より新連載を開始します。これまではWebObjectsの様々な技術を紹介してきましたが、これからは実際にアプリケーションを開発しながらその過程を逐次レポートしていく、より実践的な連載を始める予定です。実際の開発現場で問題になるようなことを積極的に取り上げていく予定ですので、ご期待ください。

    ニュース・解説

    今週の解説担当:木下 誠

    ———————————————————————-
    WWDCのセッションが一部公開
    ———————————————————————-

    WWDC 2005の情報が更新されました。それに伴い、カンファレンス・セッションとハンズ・オン・セッションのタイトルの一部が公開されています。今年のWWDCは、もちろんTigerがメインになるでしょうから、Spotlight、Core Data、Dashboard、Automator といった、すでに公開されている Tiger 技術のセッションが目を惹きます。これからも、公開されていく情報は要注目です。

    WWDC 2005の事前受付は、4月22日までです。

    WWDC 2005
    http://developer.apple.com/wwdc/index.html

    WWDC 2005 – Conference Sessions
    http://developer.apple.com/wwdc/descriptions/desc-p.html

    WWDC 2005 – Hnads on Sessions
    http://developer.apple.com/wwdc/descriptions/desc-ho.html

    ———————————————————————-
    OpenGLの最適化を解説したドキュメント
    ———————————————————————-

    Appleが、Mac OS XでのOpenGL最適化を解説したドキュメント、「Optimizing OpenGL Data Throughput on Mac OS X」を公開しています。

    OpenGLの最適化では、GPUとCPUのパワーバランスを考えることが重要になります。このドキュメントでは、CPUとGPUの最適な利用の仕方を簡単に解説しています。

    このドキュメントが主眼においているのは、頂点データの処理の最適化です。頂点データを使った描画処理、静的な頂点データ、動的な頂点データを扱う上で気を付ける点を、サンプルコードとともに解説しています。

    http://developer.apple.com/graphicsimaging/opengl/optimizingdata.html

    ———————————————————————-
    Mach-Oコードをメモリ上から実行するサンプル
    ———————————————————————-

    サンプルコード「MemoryBasedBundle」が公開されました。このサンプルは、Mach-Oのコードをメモリ上から実行する方法を紹介しています。

    DarwinのAPIである、NSCreateObjectFileImageFromMemoryを使って実行しています。また、CFBundleを使ったり、他の dyld APIを使って実行するサンプルも含まれています。

    MemoryBasedBundle
    http://developer.apple.com/samplecode/MemoryBasedBundle/MemoryBasedBundle.html

    ———————————————————————-
    Keynote 2 のファイルの読み書き
    ———————————————————————-

    Technical Q&A 1412が公開されました。Keynote 2のファイルを読み書きする方法を取り上げようとしています。

    Keynote 2のファイルは、Keynote 1.xから大きく変更されたため、そのままでは読めないようです。このQAでは、Keynote 2のファイルを読むアプリケーションを作りたい方はDeveloper Relationsまでメールを送るように、とだけ書かれています。あまり役に立たないQAでした。

    関連情報:
    Keynote 1.xのXML schemaは、こちらにあります。
    Technical Note TN 2067
    About the Keynote XML File Format (APXL Schema)
    http://developer.apple.com/technotes/tn2002/tn2067.html

    Technical Q&A QA1412
    How can I add the ability to read and write Keynote 2 documents to my application?
    http://developer.apple.com/qa/qa2005/qa1412.html

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

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

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

    2005-03-22

    目次

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

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

     本連載では、名前は知っていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。引き続き、コレクションの抽象クラス「Collection」のプロトコルを覗きながら、コレクションがどんなメッセージを受け付けるオブジェクトなのか、その“正体”を探ってゆきましょう。

     前回、コレクションとブロックの絶妙なコンビネーションで実現されるenumerating(列挙)プロトコルを先に終えたので、その前に飛ばしてしまったarithmeticプロトコルに話を戻します。

     Collectionクラスを選択した状態のブラウザで、arithmeticプロトコルをクリックしてメソッド一覧を見ると、そこには見慣れた二項演算子(二項メッセージセレクタ)が並んでいます。このことは、コレクションの仲間が、まるで数値のように演算操作を受け付けることを意味します。実際に試すとこんな感じです。

    #(3 9 8 1) * 4 ” => #(12 36 32 4) ”

     各要素に同じメッセージ(この場合「* 4」)を送ったときの返値を改めて各要素とする新しいコレクションが作られ、それが返値となっています。ただしこの場合、コレクションに送られたメッセージと同じメッセージを、要素が受け付けることが前提となっているので注意が必要です。たとえば次のようなコレクションの場合、第三の要素のシンボル「#eight」は、「* 4」というメッセージをうまく処理できないので例外があがります。

    #(3 9 #eight 1) * 4 ” => Error ”

     引数には数値以外にも同じコレクションを与えることも可能です。ただし、レシーバと引数で要素数が一致している必要があります。

    #(12 36 32 4) / #(3 9 8 1)  " => #(4 4 4 4) "
    #(4 8 12) / (1 to: 3)       " => #(4 4 4) "

     さて、このように引数によって変わる振る舞いを定義したメソッドは、いったい、どんな記述になっているのでしょうか。ちょっと想像してみてください。C++やJavaのように引数の型指定と多重定義が可能なら、想定される引数の型の数だけ関数(メソッド)を多重定義すればよいわけですが、あいにくSmalltalkには、引数の型指定も多重定義もありません。ならば、引数の型を判断して条件分岐…というのが常套ですが、Smalltalkでは別の面白い方法を使っています。

     仮にここで、#(1 2 3)に「* 4」を送信した場合を想定します。このとき#(1 2 3)が起動するのはCollection >> #*メソッドで、その定義はこれです。

    Collection >> * arg
       ^ arg adaptToCollection: self andSend: #*

     なんともあっさりしたものですね。引数に対してレシーバ(今は#(1 2 3)。selfに束縛)と、このメソッドを起動するのに用いたメッセージのセレクタ(#*)を引数にした「adaptToCollection: self andSend: #*」というメッセージを送信するひとつの式が記述されているだけです。これでは#(4 8 12)という結果の説明ができないので、このメッセージ送信によって起動する#adaptToCollection:andSend:というメソッドの定義を追ってみましょう。
    (記憶力がよく、かつ、目先の利く読者のかたの中には、前々回飛ばしたadaptingプロトコルを思い起こされる向きもあるかもしれませんね。でも、それはいったん忘れてください)。

     システム内の#adaptToCollection:andSend:の定義をブラウズするためには、ブラウザ中段の「implementors」ボタンをクリックしてポップアップするメニューから「adaptToCollection:andSend:」を選択します。すると、よりシンプルな形のブラウザが現われ、上のペインにCollection、Number、Point、Stringが列挙されます。これは、この四つのクラスに#adaptToCollection:andSend:が定義されていることを意味します。

     今は、#(1 2 3)に「* 4」というメッセージを送信したとの仮定ですので、コレクションは改めて、引数の「4」に「adaptToCollection: self andSend:#*」というメッセージを送ることになることに注意してください。結果的に、前述四つのメソッドのうち、Number >> #adaptToCollection:andSend:が起動します。このメソッドの定義は次のようなものです。

    adaptToCollection: rcvr andSend: selector
        ^ rcvr collect: [:element | element perform: selector with: self]

     前回、扱った#collect:が登場します。rcvrには、かつてのレシーバである#(1 2 3)が束縛されています。これを念頭に、メソッド本体の式を書き直すとこうなります。

    #(1 2 3) collect: [:element | element perform: #* with: 4]

     #perform:with:は第一引数に与えられたパラメータをセレクタに、第二引数に与えられたパラメータを引数にしたメッセージ送信をシミュレートするメソッドです。つまり同式は、再度改めて次のように書き直すことができます。

    #(1 2 3) collect: [:element | element * 4]

     一連のメッセージカスケードにより、最初の「#(1 2 3) * 4」が、上の式のように置き換えられ、評価されたと考えても良さそうです。なるほど、これならば#(4 8 12)が返ってくるはずですね。では、引数が4ではなく、#(4 5 6)のようなコレクションならどうでしょう。

    #(1 2 3) * #(4 5 6)

     上の「* 4」のときと同様に、「* #(4 5 6)」というメッセージ送信から派生的に生じるカスケードを追ってみてください。これは次回までの宿題にいたしましょう。なお、#with:collect:という、まだ紹介していないメソッドも登場しますが、応用や想像で補うことで解釈は可能なはずです。

    バックナンバー:
    http://squab.no-ip.com:8080/mosaren/

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

     承前……とか偉そうに書き始めたけど前回どこまでいったんだっけ?
     そうそう、Nibファイルで作成した(Interface Builderは定義だけでなくインスタンシエイトまでやることに注意してちょうだい)オブジェクトがメモリ上に場を与えられ、IBOutletやIBActionで示される相互の関係づけが完了すると、そのオブジェクトにはawakeFromNibというメッセージが送られる、というところまでだった。覚えてますか?
     ほんで、今回考えますと予告しておいたのが「awakeFromNibメッセージはどのオブジェクトに最後に送られるのか」。ひらたく言えばNibファイルの中身のオブジェクトはどんな順番でメモリ上に配置されるの? で、その最後はどれ? ということである。

     ……ほんとのことを言えばこれ、ここで書いてしまわないで、とにかくオブジェクトをたくさん作り、それぞれがawakeFromNibを受け取ったときに「はいはいはい、オレオレオレ、無事にawakeFromNibを受け取りました!」と出力させる、みたいなテストプログラムを作って実行してみて欲しいんだが……これ、実はわかんないんである。
     わかんない、ぢゃひどいか(笑)。
     正確に言うと、オレがやってみた限りにおいてはawakeFromNibメッセージが送られる順番に、なんら規則は見出せなかった。ある時はタラオバンナイ、ある時は手品好きの気障な紳士……ぢゃないけど、ちょっとNibファイルをいじるだけでその順番がコロコロと変わってしまう……。いや、変わったり変わらなかったりするんである。いつも変わるよりタチが悪い。
     具体的にどういうことかというと、AというオブジェクトがBというオブジェクトにIBOutletとして連結されているとすると、BにawakeFromNibが来たとき、BからAにアクセスは可能である。しかしその時点で、既にAにawakeFromNibが送られているかどうかはわからない。

     そもそもIBOutletは2つのオブジェクトが互いを相互にコネクトすることも可能なのだ。その場合、当然ながらどちらか片方が先にawakeFromNibを受け取るわけなので、「あるオブジェクトがawakeFromNibを受け取ったときに、そっから参照しているオブジェクトが皆awakeFromNibを受け取り済みである、というのはある種の不可能ごとなんである。
     言い換えれば、そういう状況を前提としている処理をawakeFromNibを受け取った時点で行なうように書いてはいけないのである。動かないから? そうぢゃない。動いちゃうこともあるからなおさらいけないのだ、わかるよね?

     で、このジレンマを解決するため、ようやくNSApplicationの出番が来る。Nibファイルから全てのオブジェクトを読み込んでメモリ上に配置し、そのひとつひとつにawakeFromNibを送りつけてそいつらなりの初期化を済ませると、NSApplicationは自分のDelegateに、applicationDidFinishLaunching: というメッセージを送ってくれるのだ。読んで字のごとし、「アプリケーションの起動に関する全ての処理が終わりました」ということなので、上に挙げたような前提が必要な処理に関しては、ここでNSApplicationのdelegateからそのオブジェクトにメッセージを発行すればOKとなるわけだ。
     やれやれ、この辺、わかってみれば簡単なことなんだけど説明するとナガナガとなっちまうなぁ。次回こそホントにNSApplicationの最後、「アプリケーションが終了するとき」のコトについて、これまた使用頻度の高いであろう初期設定値の初期化と保存に搦めて説明する。……この説明がまた2回に渡ったりして(汗)。
    (2005_03_17)

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

    UNIXとしてのMac OS X
    〜Perlについて(10)〜

     こんにちは、高橋真人です。
     前回は文字列の中に変数を埋め込むお話をしましたが、シングルコーテーションで展開されないのは実は変数だけではありません。
     今まで書いてきたコード例で、出力の末尾に改行を加えなかったのにはこの辺の含みがあったのです。

    print ‘Hello world¥n’;

     こんなコードがあった場合、出力は、

    Hello world¥n

    とそのままで、当然のことながら末尾は改行されません。これがPerlなのです。
     で、そうなると文字列を出力する場合には

    print “Hello world¥n”;

    とダブルコーテーションを使って書けばいいわけですが、数字などをそのまま出力するケースでは、

    print 256 …… ?

    とやったあとにどのように改行を付加すればよいのでしょうか?
    もちろん、

    print “256¥n”;

    とやれば、いいじゃないかと思われるかもしれません。それは確かにその通りです。ですが、もし数字の部分が計算式だったらどうします?

    print 128 * 2 …… ?

     さすがにダブルコーテーションで囲っても、計算式までは展開してくれるわけではありませんから、ちょっと困ってしまいますね。

     以前「print演算子はリストコンテキストを要求する」とお話ししたのを覚えておいででしょうか? つまり、こういう場合にはリストとして改行をくっつけてしまえばいいんです。

    print 128 * 2, “¥n”;

    と、こんな感じです。
     こういうやり方ができるとなりますと、当然文字列に対してもカンマでつなぐということができるわけです。

    print ‘Hello world’, “¥n”;

     「一体、こんなことをするのに何の意味があるのだ?」と思われる方もおいでかもしれません。それならば、たとえばこんなケースはどうでしょう。$という記号をスカラー変数の意味ではなく使いたい場合がありますよね。

    print “The book is $100.¥n”;

    今まで説明してきませんでしたが、Perlでは変数の宣言は必須ではありません(宣言を必須にする設定も可能です)。そのため変数は「登場したところから」使えるようになるのですが、今回のケースのようにいきなり値を設定することなしに値を読み出そうとしますと、これはエラーになってしまいます。
     実際に上記のコードを実行すると、

    The book is .

    と、まるで$100という変数には「何も値が入っていない」かのように出力されますが、Perlにおいて未初期化の変数は「undef」という値に評価されることになっているのです。
     結果的にundefが文字列として解釈されるとカラ文字列となるため、上記のような出力結果になるわけです。
     また、Cでやるようにいわゆるエスケープ文字を直前に置いてやる(¥$)ことでも望みの結果を得ることはできますが、Perlの設計思想から考えて、こういう「コードを読みづらくする要素」を余り使わずに記述できるところもメリットだと思うので、あえてシングルコーテーションを使って、特殊記号となり得る文字も「見た目のまま」使うことができる方法をご紹介しました。

    ニュース・解説

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

    Carbon ドキュメント & サンプル & SDK ナビゲーション(2005/3/4)

    【開発環境】

    随分と前から、IBMがPC970のDual Core版であるPC970MPと呼ばれるCPUを開発しているという噂が流れていました。つまり、PowerMac G5にこのCPUを2つ搭載すれば、同時に4CPUを稼働させることが可能なQuad PowerMac G5に化けるわけです。さて、近頃この噂が再熱しております。その火元は、Apple社が開発用ツールとしてデベロッパーに提供している「Computer Hardware Understanding Development Tools(CHUD)」です。つい最近、このツールの最新バージョンv4.1.0が関連サイトに登録されたのですが、その中の「Processor」環境設定のCPU稼働チェックの空きスペースが4つに増えていたのがその発端でした。その後、「何かを探すことには絶大な能力を発揮する」多くのMacデベロッパー達により、CHUDに隠されていた4CPUマシン登場の物件的証拠が次々と暴かれていきました。

    さすがに焦ったのか、Apple社は数日後にCHUDを v4.1.1に差し替え(旧バージョンは削除)、そうした証拠もすべて隠蔽してしまいました。例えば、最新版ではCPUチェックのスペースが3つに(笑)変更されております(わざとらしい…)。そうこうしているうちに、今度はIBMのサイトに、何かの手違いでPC970MP CPUの熱対策の解説文章と「Using Thermal Diodes in the PowerPC970MP(R) Processor」という技術解説ドキュメントが登録されてしまいました。Apple社からクレームが入ったのでしょうか? すかさず、次の日にはこちらも削除されましたが、Dual Core CPUであるPC970MPが存在しているのは確かな事実のようです。

    試作4CPUマシンのテスト用として「特別版」CHUDを用いていたとしても、それをそのまま一般に公開することはないでしょう。また、970MPが実際に存在することも明らかになったわけですから、間違いなく近々にQuad PowerMac G5は登場すると思われます。問題はその発表時期ですが、何やら、現在のMac OS X 10.3では4CPUには対応していないという話もあり、そこから推測すると、この新型のQuad PowerMac G5はMac OS X 10.4(Tiger)の発表と同時に登場するかもしれません。もし、もう少し発表まで時間が必要であるならば、その場はWWDC2005の基調講演と言うことになるでしょう。もっともっと高速のPowerMacの登場を望む筆者は、新PowerMac G5の発表を楽しみに待ちたいと思います(お金を貯めて…)。

    Apple社が、WWDC2005への参加を希望する学生を対象にした「ADC Accepting WWDC Student Scholarship Applications」を開始しました。指定されたテーマでレポートを書いてApple社へ送れば、WWDC2005への参加費用が免除される可能性があります。希望者の学生さんはぜひチャレンジしてみてください。

    http://developer.apple.com/wwdc/students/index.html

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

    前回から3月18日の期間中、Apple社のDocumentationサイトには新規ドキュメントがひとつも登録されませんでした。しかし、デベロッパー向けの読み物の方は2つ登録されています。「OsiriX Brings Collaboration to Medical Imaging」は、医療用のDICOM Voxelビューア(フリーウェアとして提供)の「OsiriX」の紹介です。この医療用アプリケーションは、CT撮影で得られたDICOM画像をボクセル化して表示するなどの専門的な機能の他に、Mac OS X特有の様々な機能(iPod、.Mac、QuickTime VRなど)を医療現場でうまく活用できるように工夫されています。「Tiger Developer Overview Series: Developing with Core Image」の方は、前号の木下さんの解説を参考にしてみてください。

    「OsiriX Brings Collaboration to Medical Imaging」(読み物)

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

    「Tiger Developer Overview Series: Developing with Core Image」(読み物)

    http://developer.apple.com/macosx/tiger/coreimage.html

    前回から3月18日の期間中、新規のテクニカルノートはひとつも登録されませんでしたが、新規テクニカルQ&Aの方は2つだけ登録されました。QA1415では、自力で開発したMovie Export ComponentをFinal Cut Proで認識させるための「呪文」が、QA1404の方では、アドレスブックへのCustom Propertyの正しい加え方のサンプルソースコードが紹介されています。

    QA1404「Crash in ABAddPropertiesAndTypes」
    QA1415「Movie Export Component – How to ensure Final Cut Pro recognizes your exporter」

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

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

    前回から3月18日の期間中、Apple社のSample Codeサイトには、新しいサンプルソースコードが7つ登録されました。「QuartzShapes」と「SampleUSBAudioPlugin」のみが新規のサンプルで、それ以外はマイナーな修正とバージョン変更です。

    「AudioBurn」(Cocoa関連)
    「DataBurn」(Cocoa関連)
    「ComplexPlayThru」(CoerAudio関連)
    「QDCocoaComponent」(Cocoa関連)
    「SampleFilterScheme」(Kernel関連)
    「QuartzShapes」(CoreGraphics関連)
    「SampleUSBAudioPlugin」(USB関連)

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

    【デベロップメント SDK】

    前回から3月18日の期間中、Apple社のSDKサイトには新しいSDKがひとつも登録されませんでしたが、CHUDの最新版v4.1.1がPerformance and Debugging Toolsサイトに登録されています。v4.1.1の登場数日前に、例の(笑)v4.1.0が登録されたのですが、そのバージョンは既にFTPサーバから削除されています(幻のバージョンと化しました)。

    「Computer Hardware Understanding Development Tools(CHUD)4.1.1」

    http://developer.apple.com/tools/performance/

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

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

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

    2005-03-15

    目次

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

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

     本連載では、名前は知っていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。

     前回に引き続き、コレクションの抽象クラス「Collection」のプロトコルを覗きながら、コレクションがどんなメッセージを受け付けるオブジェクトなのか、その“正体”を探ってゆきましょう。

     addingに続くarithmeticプロトコルには、前回後回しにしたadaptingに分類されるメソッド群と連携して、とてもおもしろい仕組みにより実現されたメソッドが用意されています。しかしその前に、Smalltalkのコレクションの性質の基本とも言うべきenumerating(列挙)プロトコルを先に見ておくことにします。

     さて、すでにブロックを用いた制御構造のところで触れたように、Smalltalkではいわゆるfor-nextループを次のように「メッセージ送信」のかたちで表現し、動きをシミュレートします。

    World findATranscript: nil.    "トランスクリプトをアクティベート"
    1 to: 5 do: [:i | Transcript cr; show: i]  "そこに1から5まで出力"

     このスクリプトは、次のように書いても同じ結果になります。字面では括弧が追加されただけですが、しかし、その意味するところは大きく違ってきます。

    World findATranscript: nil.
    (1 to: 5) do: [:each | Transcript cr; show: each]

     レシーバが誰で、それにどんなメッセージを送っているのか、をそれぞれについて整理すると両者の違いが明確になると思います。前者は、1に対してto: 5 do: [...] というメッセージを送っているだけ、つまり、Smalltalkにおける“式”の要件であるメッセージ送信の体裁こそ満たしていますが、そうして送られるメッセージにはそれ以上(つまり式の要件を満たす以外の)“意味”を見いだすことはできません。

     他方で後者は、(1 to: 5)というコレクション(an Interval)に対して、do: [...] というメッセージを送っています。ブロック変数を「i」から「each」に書き換えたことからも察していただけるように、#do:メソッドは、それを起動したコレクションの各要素を“列挙”し、それぞれについて引数のブロックを評価します。前者より、ずっとメッセージの内容とその意味が近いところにありそうですね。また、do: [...]ならばto: n do: [...] と違って、レシーバを別のオブジェクトに置き換えることもできます。

    World findATranscript: nil.
    (1 to: 5) do: [:each | Transcript cr; show: each].
    #(1 2 3 4 5) do: [:each | Transcript cr; show: each].
    'string' do: [:each | Transcript cr; show: each]

     enumeratingプロトコルには、レシーバの各要素について繰り返しブロックを評価する#do:の他に、注目するメソッドとして、ブロックの評価値を集めてコレクションにして返す#collect:、条件に合致したものだけ集める#select:があります。なお、evenは、整数に送ってそれが偶数かを判断し、結果をtrueあるいはfalseで返させるメッセージです。

    #(1 2 3 4) collect: [:each | each * 2]  " => #(2 4 6 8) "
    #(1 2 3 4) select: [:each | each even]  " => #(2 4) "

     collect: [...]とselect: [...]というメッセージはたいへんよく似た、つまり、引数としてブロックをひとつ添えた形態をとっていますが、引数であるブロックの役割りはかなり違うので使用に際しては注意が必要です。前者がブロックを、新たに生じさせるコレクションの要素の“発生器”として用いるのに対し、後者ではブロックを、各要素について、新しいコレクションの要素としてよいか、それとも排除するかについての判断のために用います。したがって、collect: [...]の引数のブロックには制約はありませんが、select:[...]の引数のブロックは必ず真偽値を返さなければならないという条件を満たさなければなりません。このことは、上段右端のペインで「collect:」あるいは「select:」を選択してそれぞれの定義を読むとよりよく理解できると思います。

     select: [...]の逆の役割りを果たすreject: [...]というメッセージも使えます。もちろんこれは、引数のブロック内の式の真偽を反転させたselect:[...]と同じ結果になります(定義も、ほぼ、そうなっています)。なお、oddは整数に送ってそれが奇数かを判断し、結果を真偽(trueかfalse)で返させるメッセージです。notは、真偽に送ることでその反転を促します。

    #(1 2 3 4) reject: [:each | each even]      " => #(1 3) "
    #(1 2 3 4) select: [:each | each odd]       " => #(1 3) "
    #(1 2 3 4) select: [:each | each even not]  " => #(1 3) "

     #collect:、#select:のように“基本”ではありませんが、覚えていて要所で使うとちょっとカッコイイのが#inject:into:です。たとえば、こんなスクリプトの場合、

    | sum |
    sum _ 0.
    #(1 2 3 4) do: [:each | sum _ sum + each].
    ^ sum

    …と、いうように、一時変数のsumの宣言とその初期化、また、do: [...]はレシーバを返すのでsumを改めて参照するために、合計を出すメインの式の他に、ひとつの宣言文と余計な二つの式を必要とします。#inject:into:はこうしたありがちな手続きを一時変数の力を借りずに、かつ、ひとつの式のみで済ませたいときに使います。

    #(1 2 3 4) inject: 0 into: [:result :each | result + each]

     どうして、たったこれだけで合計を算出できるのか不思議に思われるかも知れませんが、そのカラクリはCollection >> #inject:into:の定義を見れば一目瞭然です。

    Collection >> inject: thisValue into: binaryBlock
       | nextValue |
       nextValue _ thisValue.
       self do: [:each | nextValue _ binaryBlock value: nextValue value: each].
       ^ nextValue
    


    バックナンバー:
    http://squab.no-ip.com:8080/mosaren/

    小池邦人の「Carbon API 徒然草」(2005/03/11)

    Navigation Service APIの活用(その6)

    今回は、最後の自作ルーチンnavCheckImportExtention()を紹介し、それをNavGetFile()のフィルタルーチンから使うケースを解説します。また、ファイルタイプも拡張子も付いていない画像ファイルに遭遇した場合、それがオープンできるかどうかを判断するために用いる便利なルーチンも紹介します。

    前回、「拡張子のみ」でその種類を判断しなければいけないファイルのために、NULL(ゼロ)を含めたいくつかの特殊ファイルタイプもNavTypeList構造体へ追加しておく必要があると説明しました。ここでは「未定義」のファイルタイプとして、NULLの他に、’????’ 、’****’、’ ‘(スペース4つ)の3つを追加しましたが、これは筆者の経験から加えた物であり(笑)Apple社がそう定義しているわけではないのでご了承ください。また、UNIX環境からMac OS 9起動マシン経由で入ってくる画像ファイルの中には、そのタイプが’TEXT’だったりする物もありますので状況によってはさらに注意が必要です。

    以下が、navCheckImportExtention()ルーチンです。非常に原始的な方法(文字列比較)で拡張子をチェックし、ファイルタイプは「未定義」だが拡張子が目的の内容であれば、*typeに対象タイプを代入し1を返します。また、ファイルタイプが設定済みで未定義タイプでなければゼロを、未定義タイプで内容が目的の拡張子でない場合には-1を返します。今回のソースコードは誌面の関係上、チェック対象をJPEGファイルのみに限定しています。本来ならば、必要とされる画像種類の数だけ文字列比較の箇所を増やす必要があります。また、厳密に比較するならば、大文字と小文字が混在した拡張子や、4文字「.jpeg」などの、ある程度予想されるイレギュラルな拡張子にも対応する必要があるでしょう。はっきり言って、やり出したらきりがない「どこで妥協するのだ?」作業となります。

    short navCheckImportExtention( Str255 str,OSType *type )
    {
        short    len;
    
        if( *type==NULL || *type=='????' || *type=='****' || *type=='    ' )
        {                         // ファイルタイプが未定の場合(通常はNULL)
            len=*str;
            if( str[len-3]=='.' ) // 拡張子の位置をチェック
            {
                if( str[len]=='g' && str[len-1]=='p' && str[len-2]=='j' )
                {
                    *type='JPEG'; // JPEGファイルと判断
                    return( 1 );
                }
                if( str[len]=='G' && str[len-1]=='P' && str[len-2]=='J' )
                {
                    *type='JPEG'; // JPEGファイルと判断
                    return( 1 );
                }
            }
            return( -1 );
        }
        return( 0 );
    }
    


    上記ルーチンをNavGetFile()のフィルタルーチンで利用すれば、そのファイルのタイプが未定義でも、ファイル名選択ダイアログのブラウザで通常表示(グレー表示ではない)することが可能です。以下のnavFilterProc()が、navCheckImportExtention()を用いたフィルタルーチンです。

    pascal Boolean navFilterProc( AEDesc *item, void* info,
                                        NavCallBackUserData ud,NavFilterModes mod )
    {
        NavFileOrFolderInfo   *finfo;
        OSType                type;
        FSSpec                fsc;
        short                 chk;
    
        if( item->descriptorType==typeFSS ) // ファイルのFSSpec構造体を得られるか?
        {
            finfo=(NavFileOrFolderInfo*)info; // ファイルやフォルダ情報を得る
            if( ! finfo->isFolder )           // 対象はファイルのみ
            {
                AEGetDescData( item,(Ptr)&fsc,sizeof( FSSpec ) ); // FSSpecを得る
                type=finfo->fileAndFolder.fileInfo.finderInfo.fdType;// Typeを得る
                chk=navCheckImportExtention( fsc.name,&type );  // 総合チェック
                if( chk==1 )           // Typeは未定義だが対象となる拡張子である
                    return( 1 );       // ブラウザに表示する
                else if( chk==-1 )     // 対象外の拡張子である
                    return( 0 );       // ファイル名をグレー表示にする
            }
        }
        return( 1 ); // Typeはちゃんと定義されているのでブラウザに表示する
    }
    


    利用するための登録は簡単です。NavGetFile()を実行する時に、以下のようにフィルタルーチンとして引数で渡してやります。NavFileOrFolderInfo構造体の詳しい内容についてはNavigation.hを参照してください。また、フィルタルーチンで表示判別の対象となるファイルは、先んじてNavTypeListHandle(NavTypeList構造体)で設定したファイルタイプを持つ物のみとなりますので、くれぐれも注意してください。

    NavGetFile( NULL,&reply,&opt,NULL,NULL,navFilterProc,list,NULL );

    ファイルタイプが未定義でも、ちゃんと拡張子があれば種類の判断は可能なのですが(嘘の拡張子が付いていたらダメ)、中には両方とも存在しないファイルがあります。こうなると、「ファイルの中身」をサーチし、その種類を判断するという「最終手段」を取らざるをえなくなります。具体的に言えば、画像ファイルのヘッダ情報を読み込み、そこに正しい情報が記載されているかどうかをチェックするわけです。しかし、すべての画像ファイルについて「いちいちそこまでやってられない!」と言うのが開発者の本音なわけです(笑)。そこで最後に、QuickTime GraphicsImporterコンポーネントの能力を使い、ファイルのMIME(Multipurpose Internet Mail Extensions)情報を得ることで、そこからファイル種類を判別するnaviCheckMIMEList()ルーチンを紹介しておきます。

    short naviCheckMIMEList( FSSpec *fsc,OSType *type )
    {
        QTAtom                    atom=NULL;
        OSType                    type1=0;
        long                      size=0;
        short                     ret=1;
        QTAtomContainer           cont;
        Str255                    str;
        Ptr                       pp;
        GraphicsImportComponent   gi;
    
        *str=0;
        if( ! GetGraphicsImporterForFile( fsc,&gi ) ) // FSSpec経由でImporterを得る
        {
            GraphicsImportGetMIMETypeList( gi,&cont ); // QTAtomContainerを得る
            if( atom=QTFindChildByID( cont,NULL,'mime',1,NULL ) ) // QTAtomを抽出
            {
                if( ! QTGetAtomDataPtr( cont,atom,&size,(Ptr *)&pp ) ) // MIME抽出
                {
                    *str=size;
                    BlockMove( pp,str+1,size );                   // 文字列に変換
                    if( cmpString( str,"¥pimage/x-photoshop" ) )  // 文字列の比較
                        type1='8BPS';
                    if( cmpString( str,"¥pimage/x-mac" ) )  // これは自作ルーチン
                        type1='PNTG';
                    if( cmpString( str,"¥pimage/x-bmp" ) )
                        type1='BMPf';
                    if( cmpString( str,"¥pimage/pict" ) )
                        type1='PICT';
                    if( cmpString( str,"¥pimage/jpeg" ) )
                        type1='JPEG';
                    if( cmpString( str,"¥pimage/tiff" ) )
                        type1='TIFF';
                    if( cmpString( str,"¥pimage/gif" ) )
                        type1='GIFf';
                    if( cmpString( str,"¥pimage/png" ) )
                        type1='PNGf';
                    if( cmpString( str,"¥papplication/pdf" ) )
                        type1='PDF ';
                    if( type1 )
                    {
                        *type=type1;  // 得られたファイルタイプを代入
                        ret=noErr;    // Typeを得られればnoErr(ゼロ)が返る
                    }
                }
            }
            CloseComponent( gi ); // GraphicsImporterコンポーネントを解放
        }
        return( ret ); // Typeが得られれなければ1が返る
    }
    


    このルーチンは、「正体不明」のファイルの正体を突き止める最終手段としてそこそこ役に立ちます。今回は、MIME情報も得たいケースを考え、QTAtomから抽出したMIMEタイプを一度パスカル文字列に変換してから比較していますが、もちろんこの手間を省き直接バイナリ比較してもかまいません。前回も言及しましたが、現在のNavigation Serviceは「拡張子」の扱が非常に貧弱なのが最大の弱点です。それだけ、以前からMacintoshが採用している(今でもしているが…)ファイルタイプと言う仕組みが理解しやすく取り扱いが楽だった証拠にもなります。しかし、こうなってしまった現状としては、この「鬼っ子」をもう少しうまく手なずけるための有用なAPIが、早急にNavigation Serviceに実装されることを切望したいと思います。

    次回は「Navigation Service APIの活用」の最終回となります。FSSpecの代わりにFSRefを得るために有用なシートウィンドウ版の「フォルダ選択ダイアログ」と「ファイル名選択ダイアログ」を紹介したいと思います。

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

     前回に引き続き運用についての解説です。前回はアプリケーションのインストール方法を説明しましたが今回は運用環境のセットアップについてみていきたいと思います。

    運用環境のセットアップ

     WebObjectsの運用プラットフォームとしてはWindowsやSolarisもサポートされていますが、ここではMac OS X Serverでのセットアップ方法について解説します。Mac OS X ServerにはあらかじめWOの運用ライセンスが付属しており、さらにv10.3からはOSの一部として最初から運用環境が組み込まれているため別途運用環境をインストールする必要がなく、短時間で環境をセットアップすることができます。
     ただしMac OS X Server v10.3をインストールしただけですと、運用環境の中核となるwotaskd(WebObjects task deamon)はまだ停止状態になっています。通常はOS起動時にwotaskdを起動させて常駐させておく必要がありますので、まずはその設定が必要になります。
     Mac OS X Server v10.3にはあらかじめwotaskdの起動スクリプトが用意されていますが、wotaskdの実行命令がコメントアウトされた状態になっていますのでコメントを外さなければなりません。コメントを外しておけばOS起動時にスクリプトが自動的に実行されてwotaskdが起動します。

    ・wotaskd起動スクリプト
    /System/Library/StartupItems/WebObjects/WebObjects
    ・実行命令
    “${WOSERVICE}” -appPath “${WOTASKD}” >/var/log/webobjects.log 2>&1 &

    運用環境の動作確認

     wotaskdはポート1085番で起動するように設定されていますので、Webブラウザからポート1085にアクセスしてレスポンスがあればwotaskdの起動が確認できたことになります。起動スクリプトをみると分かりますが、wotaskdのログがログファイルに保存されていますので、ログファイルを参照して起動を確認することもできます。

    ・wotaskdの起動確認
    http://localhost:1085
    ・wotaskdのログファイル
    /var/log/webobjects.log
    ・正常に起動した場合のログ
    [2005-02-23 16:15:58 JST]

    The URL for webserver connect is:
    http://192.168.0.1/cgi-bin/WebObjects/wotaskd.woa/-1085
    The URL for direct connect is:
    http://192.168.0.1:1085/cgi-bin/WebObjects/wotaskd.woa
    [2005-02-23 16:15:58 JST]
    Waiting for requests…

     Mac OS X Server v10.3の場合は若干注意が必要なところがありまして、以前はroot権限でwotaskdが起動されていたのですが、v10.3からはappserverというユーザでwotaskdが起動されるようになりました。このためパーミッションの設定には注意が必要です。

    Monitorの起動

     wotaskdの起動が確認できれば次はMonitorの起動です。MonitorとはWOの運用環境を設定するツールで、Webアプリケーションとして実装されています。MonitorはWebObjectsで開発されており、起動するには起動スクリプトを実行します。

    ・Monitorの起動スクリプトのパス
    /System/Library/WebObjects/JavaApplications/JavaMonitor.woa/JavaMonitor

     開発環境でMonitorを起動した場合は、WebブラウザにMonitorのトップページが自動的に表示されますが、開発環境上では自動的に表示されません。そこで、ターミナル上でMonitorの起動スクリプトを実行しますとwotaskdのログと同様のものが表示されますので、そこに表示されるURL(最後から2行目)からMonitorのトップページにアクセスすることができます。
     MonitorはWebアプリケーションですので、ネットワークを経由して他のマシンから操作することもできます。

    Monitorの設定

     Monitorを起動したらまずはパスワードの設定をおこなってください。パスワードの設定は「Preferences」画面でおこないます。パスワードを設定しておきますと、Monitorがパスワードで保護され、Monitorを起動したときにパスワードの入力が求められるようになります。
     Monitorが利用できれば自由にアプリケーションを停止できたりしますので危険ですし、Monitorでパスワードを設定することによりwotaskdがポート1085で公開しているデータを保護することもできます。

     パスワード設定ができましたら、次に「Hosts」画面でホストの登録をおこないます。ここでのホストとはwotaskdが起動しているマシンのことです。WOはWebサーバとアプリケーションサーバ(wotaskdが起動しているサーバ)を分けることもできますし、アプリケーションサーバを複数配置して負荷分散をおこなうこともできますが、まずはすべて1台のマシン上で動作させる単純な構成から始めるのがよいでしょう。

     ホストの設定が完了すればこれでいよいよアプリケーションを運用できる準備がととのったことになりますが、「Site」画面でHTTP Adaptor URLの設定をおこなっておくと便利です。この設定をおこなっておくことで運用中のアプリケーションにMonitor上から直接リンクがはられます。

    ・HTTP Adaptor URLの設定例
    http://192.168.0.1/cgi-bin/WebObjects

     さて今回は以上ですが、次回はアプリケーションの登録や設定方法を解説する予定です。

    ニュース・解説

    今週の解説担当:木下 誠

    ———————————————————————-
    Core Imageを解説した文書が登場
    ———————————————————————-

    Appleが、Tiger Developer Overview Seriesの最新作「Developing with Core Image」を公開していました。Tigerで導入される、2次元画像処理ライブラリであるCore Imageの概要を説明しています。

    Core Imageは、アプリケーションから使える強力な画像ライブラリです。その特徴は、豊富なフィルタにあります。フィルタはImage Unitと呼ばれるモジュールで提供され、その数は100近くに上ります。簡単に言えば、Web Kitがあればブラウザが簡単に作れるように、Core Imageがあれば誰でもPhotoshopが作れると言えるでしょう。

    このImage Unitにアクセスするには、Quartz Coreフレームワークを利用します。このフレームワークは、CIImageやCIFilterといったObjective-CのAPIを提供しており、Cocoaアプリケーションからはシームレスに使うことができるようです。CベースのAPIが提供されるかどうかは不明です。

    Core Imageのもう一つの特徴は、ハードウェア・アクセラレータのサポートを受けられることにあります。近年、爆発的に性能を上げているGPUの命令セットを直接使えることになるようです。そのために、Image Unitを作成するときはCIKernelという言語を使います。CIKernelはCに似たスタイルで、Open GL Shading Languageのサブセットになっています。これにより、ポータブルでありながら最大のパフォーマンスを得られるようになっています。

    また、TigerにはCore Imageをテストするためのツールが2つ付いてくるそうです。1つはCore Image Fun Houseと呼ばれるもので、1枚の画像に複数のImage Unitを適応していくものです。去年のWWDCキーノートで使われたツールがベースになっているものと思われます。もう1つは、Quartz Composerと呼ばれるもので、グラフィカルにImage Unitを接続していくツールです。このツールでは、Image Unitのインプットとアウトップを細かく制御することができるようです。また、アニメーションを作成して、スクリーンセイバーなどで使うことができます。

    Developing with Core Image
    http://developer.apple.com/macosx/tiger/coreimage.html

    ———————————————————————-
    Eclipseのチュートリアルが公開
    ———————————————————————-

    Appleが、Java開発環境であるEclipseの使い方を解説した「Developing Java Applications on Mac OS X with Eclipse」を公開しています。Eclipseで開発を始めるためのチュートリアルです。

    Eclipseは、Javaで書かれたIDE(統合開発環境)で、Java開発ではほぼ標準の地位を占めます。Mac OS XでEclipseを使う利点は、もちろんその高い完成度もありますが、LinuxやWindowsといった複数プラットフォームが混在した開発体制でも、プロジェクトファイルなどを共有できる、ということが挙げられます。

    Appleが今回公開した記事では、Eclipseを使い始めるための3つの例を説明しています。1つ目は、いつも通りのHelloWorldの作り方。2つ目は、Swingを用いたプロジェクト。そして3つ目は、SWT(Standard Widget Toolkit)を用いた例です。

    Developing Java Applications on Mac OS X with Eclipse
    http://developer.apple.com/tools/usingeclipse.html

    ———————————————————————-
    Dashboard Widget Contest受賞作品発表
    ———————————————————————-

    Appleが、Dashboard Widget Contestの受賞作品を発表していました。「Send SMS」と「WikityWidget」の2つが発表されています。

    Send SMSは、ウィジェットからSMS(Short Message Service)を送るものです。SMSは、アメリカの携帯電話でいまだに主流の、150文字程度のテキスト送信サービスです。このウィジェットは、XMLHttpRequestを利用したテキストの送信と、Address Bookからのアドレス取得がポイントとなっています。

    WikityWidgetは、Wikiを利用したノートパッドです。Wikiを利用して、ノートの読み込み、保存を行っています。特徴は強力な検索機能のようです。また、プラグインを作成してJavaScriptからSQLiteへのアクセスを行っているようです。何に利用しているのかは分かりませんが。

    このように見てみると、少し高機能なウィジェットを作ろうとすると、プラグインの助けがすぐ必要になることが分かります。CSS + JavaScriptでできることはかなり限られると思われるので、ウィジェット用単機能プラグインの開発は需要が高いかもしれません。

    The Apple Dashboard Widget Contest
    http://developer.apple.com/macosx/tiger/dashboard/

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

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

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

    2005-03-08

    目次

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

                

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

     本連載では、名前は知っていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。

     Smalltalkでは、「Object」クラスを頂点とする単一継承の継承ツリーの中にすべてクラスが組み込まれています【註】。この継承ツリーをたどりながらそれぞれの定義を見てゆくことで、注目するクラスに属するオブジェクトがどんな特性を有するのかをよりよく知ることができます。

     コレクションは、「Object」を直接のスーパークラスとする「Collection」を頂点に巨大なサブツリーを形成します。前回挙げた「Array」「OrderedCollection」「Dictionary」「Set」「Bag」「Symbol」「String」「Interval」「SortedCollection」も、そのサブツリーの中のどこかに定義されています。念のため、たがいの位置関係を次に示しておきましょう。「字下げ」により、そのクラスが、ひとつ上の字下げレベルのクラスのサブクラスであることを表現しています(たとえば「String」は「ArrayedCollection」のサブクラスで「Symbol」のスーパークラスである、といった具合に)。

    Collection
     SequenceableCollection
      ArrayedCollection
       Array
       String
        Symbol
      OrderedCollection
       SortedCollection
      Interval
     Set
      Dictionary #()
     Bag
    


     ここで新しく登場したSequenceableCollectionとArrayedCollectionは、Collection同様、それぞれの直下のサブクラス群を束ねるために存在する抽象クラスです。抽象クラスというのは、そのインスタンスの生成・使用は想定しないけれど、他のクラスのスーパークラスになることで、全体の継承関係を整理する目的で存在する特殊なクラスのことを言います。C++やEiffelなどでは、もっぱら多態性実現のために、型宣言において頻繁に用いられますが、Smalltalkでは完全に裏方に徹しており、せいぜいサブクラスに共通するメソッドを保持する場所…程度の意味しかないため、コード中でその名を見ることはほとんどないと思います。

     ではまずSmalltalkのコレクションオブジェクトの基本的な機能を知るために、Collectionの定義を覗いてみましょう。

     文字が入力できる適当な場所で「Collection」とタイプして選択後、browse it(Cmd-B)してCollectionの定義を呼び出します。

    [fig.A]ブラウザでCollectionクラスを選択したところ。
    http://squab.no-ip.com:8080/mosaren/uploads/33a.png

     ちなみに、ここで下のコードペインに目をやると、CollectionがObjectの直接のサブクラスであることが確認できます。

    Object subclass: #Collection
       instanceVariableNames: ''
       classVariableNames: 'RandomForPicking '
       poolDictionaries: ''
       category: 'Collections-Abstract'
    


     また、この状態で、上段左から2番目のペイン下にある「?」ボタンを繰り返しクリックすることで、Collectionクラスのコメント、Collectionクラスを中心に見た、巨大なスーパークラス群およびサブクラス群が形成する巨大なサブツリーをトグルさせながら閲覧することも可能です。

    [fig.B]Collectionクラスのコメントを呼び出したところ。
    http://squab.no-ip.com:8080/mosaren/uploads/33b.png

    [fig.C]Collectionを含むサブツリーを一覧したところ。
    http://squab.no-ip.com:8080/mosaren/uploads/33c.png

     本題に戻ります(なお、作業を続けるにあたって、上の「?」ボタンのトグル状態は気にする必要はありません)。まず上段左から3番目のペイン(プロトコルリスト、あるいは、メソッドカテゴリリスト、メッセージカテゴリリストとも言う)からaccessingをクリックして選択してください。

    [fig.D]accessingプロトコルを選択したところ。
    http://squab.no-ip.com:8080/mosaren/uploads/33d.png

     すると、accessingプロトコルに属するメソッド名(セレクタ)が続く右側のペインで一覧できます。ここでコレクション共通の機能として注目したいのは、#sizeと#atRandomです。コレクションに対して、sizeというメッセージを送信することで要素数を、atRandomというメッセージを送信することで任意の要素を取り出すことが可能です。

    Collection allInstances class ” => Array ”
    Collection allInsntaces size ” an Arrayの要素数確認 ”
    ($a to: $z) size ” an Intervalの要素数確認 ”
    #(‘this’ #is $a 10) atRandom ” an Arrayから任意の要素選択 ”
    ‘squeak’ atRandom ” a Stringから任意の文字選択 ”
    ($a to: $z) atRandom ” $aから$zまでのa Characterから任意選択 ”

     次のadaptingプロトコルはいったん無視して、addingプロトコルに属するメソッドを見ます。ここで注目しておきたいのは、#add:、#addAll:です。「add: newObject」というメッセージ送信により、コレクションへの要素(newObject)の追加、「addAll: aCollection」によりaCollectionに含まれる要素の追加を期待します。

    | collection |
    collection _ OrderedCollection new.
    collection add: 'this'.
    collection addAll: #(#is $a 10).
    ^ collection   " => an OrderedCollection('this' #is $a 10) "

     ただし、こうした要素の追加を期待するメッセージ送信は、当然、要素の追加を許すタイプのコレクションにしか通用しないので注意してください。なお、要素の追加ができないan Array、a String、a Symbol、an Intervalなどに、これらの要素追加用メッセージを送ると例外が生じます。

    ‘string’ add: $s
    ” => Error: This message is not appropriate for this object ”

     次回も引き続き、Collectionのプロトコルを見つつ、コレクションに共通な機能をさぐってゆきましょう。

    註: SqueakシステムではObjectのスーパークラスとして、新たにProtoObjectという特殊なクラスが設けられていますが、通常はObjectが頂点であると考えていて差し支えありません。

    バックナンバー:
    http://squab.no-ip.com:8080/mosaren/

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

     NSApplicationにまつわる話の最終回。前回の最後でも書いたように、重要極まりない初期化と終了に関わるお話である。
     Cocoaの初期化というと、普通、それまでCだけを使ってプログラムを書いて来たヒトや、C++を使っていたけれど実はあんまりよくオブジェクト指向というものがわかってなかったヒトには戸惑うところが多いようだ。「なんでInterfaceBuilderでヒモづけしているのにこのオブジェクトがnilなんだよぉ」とか、思ったことありませんか? そんなこと思うほど使ってない? ああそうですか。

     例えばInterfaceBuilderでNSObject(いや、別にNSObjectControllerでもいいんだけどさ)をサブクラスしてOurObjectつうのを定義し、これをウィンドゥ内のあるテキストフィールドのdelegateにしよう。テキストフィールドをコントロールキーを押しながらクリックし、表示されるラインを今作ったオブジェクトに繋ぐ。Info ウィンドウのコネクションで、delegateに指定する。……これで、このテキストフィールドの文字列をユーザーが変更するたび、delegateになったオブジェクトにはその通知が来る。ここまではいいかな。
     だけど、delegateのオブジェクト側としては起動した最初に、そのテキストフィールドに入っている初期値を動的に設定したいとする。この場合、delegateによる通知がなくても、オブジェクト側から件のテキストフィールドにアクセスできないといけないので、新たにIBOutletを作ってそこにテキストフィールドを繋ぐことになるよね。これで、うまく図示できないけどNibファイル上で:

     テキストフィールドのIBOutlet:delegate —–> OurObject

     OurObjectのIBOutlet:textField —-> テキストフィールド

    という相互参照が成ったことはお解りいただけると思う。
     では、こういう定義がなされたNibファイルを使ったアプリケーションが起動されたとき何が起きるか。当然ながらOurObjectとテキストフィ−ルド(というか実際にはこのテキストフィールドを内包するヴュウあるいはウィンドウだけどね)の定義が同時にメモリ上に読み込まれて配置されるなんてこたぁない(1つのCPUが2つの仕事を同時にすることはない)。
     OurObjectがまずメモリ上に確保されたとすれば(initメッセージが送られる)、その時点ではこいつのIBOutlet:textFieldは空である。だってそのテキストフィールドはそのときメモリ空間のどこにもまだ存在しないんだから、当然だよね? もしテキストフィールドの方が先でも同じ、このクラス、NSTextFieldがinitWithFrame: メッセージ(NSViewのサブクラスだから初期化はこれになる)を受け取ったときにはdelegateは空になってる。
     ところがこれでは、例えば上に書いたOurObjectによるテキストフィールドの初期化ができない。できないでしょ? そこで「全てのオブジェクトが確保され、IBOutletによる参照も実アドレスで初期化された」状態になると、NibファイルからオブジェクトおのおのにawakeFromNibというメッセージが送られる。つまり個々のオブジェクト単位の初期化はこのタイミングで行なえばいいというわけだ。
     ……ここまで書いてようやく話はNSApplicationに戻るのだが……、ああ、最終回のつもりが紙幅が尽きてしまった。しょうがないのでこれをあと1回……2回になるかも……続けることにする。次回考えるのは「awakeFromNibメッセージはどのオブジェクトに最後に送られるのか」である。暇があったら考えておいてくださいな。ではまた次回。
    (2005_03_03)

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

    UNIXとしてのMac OS X
    〜Perlについて(9)〜

     こんにちは、高橋真人です。
     今回は、連載の第59回で予告した「シングルコーテーションとダブルコーテーションの違い」についてお話しします。
     シングルコーテーションはCではご存知のように文字定数に使われますが、鷲見さんの連載でおなじみのSmalltalkでは文字列の表現に使われます。ちなみにSmalltalkの場合、ダブルコーテーションで囲ったものはコメントと見なされます。
     さてPerlの場合はどうなのでしょう。
     Perlでは文字列にはシングルコーテーションもダブルコーテーションも使うことが可能ですが、両者には少し違いがあります。
     たとえば、Cの入門でおなじみのprintf()という関数はPerlにも存在します。しかしPerlにおいてはprintfの登場はCの場合ほど多くはありません。なぜならPerlでは文字列の中に変数を埋め込むことができるからです。たとえば、

    $number = 256;
    print "The number is $number.";

    と書くと、文字列の中の$numberの部分は256に置き換えられ、出力は、

    The number is 256.

    となるのです。
     もうお分かりかと思いますが、ダブルコーテーションで囲った文字列では、変数はその保持する値に置き換わった上で埋め込まれます。ですが、シングルコーテーションで囲まれた文字列ではこの置き換えは起こりません。
     従って、

    print ‘The number is $number.’;

    というコードの出力は、

    The number is $number.

    となるということです。
     ところで、上記のケースで$numという変数も存在していたらどうなると思いますか? つまり、以下のようなケースです。

    $num = 100;
    $number = 256;
    print "The number is $number.";

     ここでは、256、つまり$numberの方が出力されます。つまり、単語の区切りが変数の識別にも使われているということです。
     では、もし$numberの定義がなかったらどうなるのでしょう? つまり、以下のようなケースです。

    $num = 100;
    print "The number is $number.";

     これでもやはり、変数は$numberであると見なされ、出力結果は

    The number is .

    となります。$numという変数があるからといって、「number」という単語のまとまりが不自然に分割されることはないのです。で、$numberという変数の定義は行われていないので、この部分は結果的に何も出力されません。
     では、以下のような場合はどうでしょう?

    $price = 100;
    print "The price of this product is $priceyen.";

     気を利かせて100yenと出てくれてもいいようなものですが(笑)、残念ながらここでも「$priceyen」という変数が未定義なので、そうはなりません。
    「じゃあ、ちゃんと100yenと出させることはできないのか?」と思われるかもしれませんが、もちろんそんなことはありません。
     このような場合、Perlに「変数の区切り」を教えてやる必要があります。やり方は以下のような感じです。

    $price = 100;
    print "The price of this product is ${price}yen.";

     つまり、変数の部分を{}で囲ってやることで、Perlは「price」という単語を識別し、$priceという変数を認識することができるというわけですね。
     このようにPerlでは変数には先頭に特別な記号が付くという決まりがあるために、文字列の中に直接変数を埋め込んだ記述が可能となるわけですが、代わりに今紹介したような「ちょっとつじつま合わせっぽい」やり方も時には必要とされるわけです。
     こういうところを私は「Perlの少し美しくない部分」だと思うのですが、皆さんはどう思われるでしょうか?

    ニュース・解説

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

    Carbon ドキュメント & サンプル & SDK ナビゲーション(2005/3/4)

    【開発環境】

    最近は、QuickDraw APIを使うのを止め、積極的にCoreGraphics(Quartz 2D)APIの方を活用してアプリケーションを開発しております…。まあAPI自体の差し替えについては95%以上問題ないのですが、全面的に差し替えようとすると、何かと不都合や面倒なケースに遭遇します。特にCoreGraphicのディフォルト座標系が、Window ManagerやControl Managerと異なるのは実にうっとおしいですね(簡単に変更はできるが…)。それから、整数による座標、加えてCopyBits()、PICT、Polygon、Regionなどの「名作」との決別は、古くから継続しているアプリケーションによっては大きな障害になりうるでしょう。また、別のManagerやQuickTimeにQuickDrawに依存したAPIが残っている場合が多々あり、そうしたAPIを使用しなければいけない場合などは、はっきり言って矛盾を禁じ得ません(笑)。QuickDrawからCoreGraphicsへ切り替える作業については、以下のドキュメントが大変参考になります。

    「Transitioning to Quartz 2D」

    http://developer.apple.com/documentation/Carbon/Conceptual/QuickDrawToQuartz2D/index.html

    幾つかの「懸案事項」については、ドキュメント内でも「機能が不足している」と正直に認めておるのですが(笑)、はたしてこうした部分がMac OS X 10.4(Tiger)で見事に解決されているのでしょうか? 注目したいところです。

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

    前回から3月4日の期間中、Apple社のDocumentationサイトには新規ドキュメントが10登録されました。すべてマイナーな改訂版です。今回からドキュメントタイトルの後ろに、どんなテクノロジーに関係する資料なのかを記号で示すようにしてみました。CBはCarbon、COはCocoa、CFはCore Foundation、DWはDarwin、DVはDevice、ASはApple Script関連のドキュメントであることを意味しています(ちなみにCFはCBにもCOにも関係している)。こう見ると、CarbonとCocoaの両方から共通で使える技術が増えてきたことが分かります(CF関連資料はPDF版を用意して欲しい!)。また、デベロッパー向けに2つの読み物が登録されています。ここで解説されている両技術は、Mac OS Xが登場したおかげで積極的に活用できるようになったわけでして、デベロッパーとしては大変喜ばしいことです(笑)。「Accessing SQL Data in Apple Remote Desktop 2」の方は、前号の木下さんの解説も参考にしてください。

    「Bundles」CF
    「Certificate, Key, and Trust Services Reference」CB&CO(PDFあり)
    「Communicating With Objects」CO
    「Core Foundation Reference」CF
    「Internationalizing Your Software」CB&CO(PDFあり)
    「Kernel Extension Concepts」DW(PDFあり)
    「Mac OS X Man Pages」DW&DV
    「Multithreading Programming Topics」CB&CO(PDFあり)
    「Plug-ins」CF
    「XML-RPC and SOAP Programming Guide」AS&CB&CO(PDFあり)

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

    「Developing Java Applications on Mac OS X with Eclipse」(読み物)

    http://developer.apple.com/tools/usingeclipse.html

    「Accessing SQL Data in Apple Remote Desktop 2」(読み物)

    http://developer.apple.com/appleapplications/ardsql.html

    前回から3月4日の期間中、新規のテクニカルノートはひとつだけ登録されました。また、新規テクニカルQ&Aの方は3つ登録されています。TN2110はMac OS X 10.3にインプリメントされているJavaのバージョンの種類とその認識方法が示されています。QA1411とQA1413については、前号の木下さんの解説を参考にしてください。現状のQuickTime 6におけるファイルハンドリングは、内部的にFSSpecに「頼り切っている」という証拠がボロボロと出ております(笑)。

    TN2110「Identifying Java on Mac OS X」

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

    QA1304「Movie Export – Always fill in the MovieExportGetDataParams dataSize field」
    QA1413「NativePathNameToFSSpec returns bdNamErr (-37) error」
    QA1411「Sequence Grabber preallocates large file when recording」

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

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

    前回から3月4日の期間中、Apple社のSample Codeサイトには、新しいサンプルソースコードが3つ登録されました。「BrideOfMungGrab」と「HelpHook」については、前号で木下さんが紹介されています。

    「SwapLAF」(Java関連)
    「HelpHook」(Java関連)
    「BrideOfMungGrab」(QuickTime&Sequence Grabber関連)

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

    【デベロップメント SDK】

    前回から3月4日の期間中、Apple社のSDKサイトには新しいSDKが2つ登録されました。「Kernel Debug Kit 」は、最近登場したMac OS X 10.3.8に対応したバージョンです。

    「CoreAudio SDK v1.3.4」
    「Kernel Debug Kit 10.3.8」

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

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

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

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

    2005-03-01

    目次

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

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

     本連載では、名前は知っていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。

     「コレクション」と呼ばれるオブジェクトは、Collectionとそのサブクラス群によって定義され、文字通り、要素の集まりを表現するために使います。どのようなルールで要素を集めて扱うか、あるいは、どんな要素を対象にするのかといった目的別に使い分けます。Smalltalkのコレクションは非常に数が多く、その多さに初心者は(特に他の言語に精通している人ほど)面食らってしまうようです。どのくらい多いか、その数を知ることは簡単にできます。

    Collection allSubclasses size ” => 88 ”

     Smalltalkシステムが返してきたこの答えを信じるならば、なんと90個近いコレクションがあることになるわけです。もっとも「これをすべて覚えなければならないのか…」とのご心配にはおよびません。そのほとんどは特殊な用途向けに用意されたもので、普段から覚えておく必要があるのはほんのいくつかにすぎないからです。

     Smalltalkシステム、つまり暫定ダイナブック環境においては、他のOSに比べて、あらゆる情報がすべてオープンで、しかも異常なほど容易にアクセスできるため、つい、ひとつひとつ実際に手にとって確かめたくなってしまいがちです。そうした姿勢自体は悪いことではないですし、それ、つまりエンドユーザーが自身の使用しているシステムのしくみを知りたくなるよう仕向けることは、まさにアラン・ケイの狙いでもあるわけですが、初心のうちはほどほどにしておかないと、情報の多さに押しつぶされてしまいます。うまく捨て目を利かせつつ、適度に無視するのが、Smalltalkとうまくつき合うためのコツだと言えそうです。

     さて。普段から覚えておいたほうがよいいくつかのコレクションというのは、なにも特別なものではなく、Cocoaに用意されているコレクションとほぼ一致します。これはけっして偶然というわけではありません。なぜなら、Cocoaの前身であるNEXTSTEP(のAPI)は、Smalltalkの雑然としたクラス群をライブラリとして使いやすく整理・再構築したものだとも言えるので、むしろ当然のことでしょう。

     SmalltalkのコレクションとCocoaのコレクションの対応は、おおよそ次の通りです。

    NSArray …… Array
    NSMutableArray …… OrderedCollection
    NSDictionary …… Dictionary
    NSSet …… Set
    NSCountedSet …… Bag
    NSString …… Symbol
    NSMutableString …… String

     念のため、それぞれがどんな特徴を持っているかについても簡単に紹介しておきます。

     Arrayはすでにご存じでお馴染みの「配列」です。各要素は前後関係を保持しつつ管理され各々にインデックスが振られます。ただ、Cocoaとは異なりSmalltalkではインデックスは0からではなく1から始まり、最後の要素のインデックスは全要素数に一致します。また、NSArrayと違ってArrayでは、要素を変更することができますが、要素数の増減は(NSArray同様)できません。要素数を増減させる用途には、Arrayではなく、OrderedCollectionを使います。

     Dictionary、Set、Bagは、要素の順番を考慮しないコレクションです。Dictionaryは名前のとおり「辞書」です。「キー(key)」に「値(value)」を対応付けて要素として管理してくれます。Setは要素の重複を許しません。すでに存在する要素を追加しようとしても無視されます。Setの「要素の重複を許さない」という制約を取り払ったのがBagです。

     SymbolとStringは、Array同様、これまでも何度か登場していますね。Symbolには、NSMutableStringに対しNSStringの持っているImutableであるという性質の他に、同値なら同一オブジェクトであることを保証する(つまり、同内容のコピーの存在を許さない)という特性も備わっています。「= arg」はレシーバとargが同値かどうかを、「== arg」は同一かどうかをテストしたいときに送るメッセージです。

    #symbol = #symbol copy ” => true ”
    #symbol == #symbol copy ” => true ”
    ‘string’ = ‘string’ copy ” => true ”
    ‘string’ == ‘string’ copy ” => false ”

     シンボル、文字列に関しては、大島芳樹さんら日本人Squeakユーザーの有志により構築された多国語対応版を用いることで、いわゆるマルチバイト文字列への対応も可能です。多国語版Squeakをベースにした日本語版は、次のサイトより入手できます。日本語版については、現在最新版の開発が最終段階に入っているようなので、近いうちにご紹介できると思います。

    http://squeak.hp.infoseek.co.jp/nihongo.htm

     以上の他に、範囲や等差数列を表わすのに用いるInterval、常に要素がソートされた状態で保たれるSortedCollectionを知っておけば、当面、コレクション関係で不自由はしないはずです。

    バックナンバー:
    http://squab.no-ip.com:8080/mosaren/

    小池邦人の「Carbon API 徒然草」(2005/02/25)

    Navigation Service APIの活用(その5)

    今回は、navMyGetFile()から呼ばれているnavGetImportTypeList()とnavMakeTypeList()の2つの自作ルーチンを解説することで、ファイル選択時の「ファイルタイプ」と「拡張子」の混在問題について考えてみます。

    特殊なアプリケーション(例えばファイルメンテナンスやユーティリティ関連など)を除き、一般的なアプリケーションでは、ユーザが選択すべきファイルの種類は限定されています。選択しても意味の無いファイルは、ファイル選択ダイアログのブラウザで選択不可(グレイ表示)にしておくのが、Macintoshユーザインターフェースにおける一般的なルールです。具体的には、選択対象であるファイルタイプの配列(NavTypeList構造体)をNavTypeListHandleへ格納してから、NavGetFile()へ引数として渡してやります。アプリケーション自身で作成されたドキュメントをオープンする場合には、通常そのファイルタイプはひとつで固定されていますので、NavTypeListを作成することは至極簡単な作業となります。しかし、場合によっては、渡すべきNavTypeListの内容やその総数を確定できない場合もあります。

    その代表的な例が、様々な画像ファイルをオープンするために「QuickTime Importer」を使う場合です。QuickTimeがバージョンアップする度に、Importerでオープン可能な画像ファイルの種類は増加していきました。つまり、インストールされているQuickTimeのバージョンにより、対応ファイルの種類の総数が異なるわけです。まあ、「オープンするファイルはPICT、TIFF、JPEG、8BPS(Photoshop)だけに固定だ!」と決めつけてしまえば、その4タイプをNavTypeListに代入するだけで済むので話は簡単です。しかし、それではせっかくのImporterの強力な能力を制限してしまうことになります。それを避けるのためには、現バージョンのQuickTime Importerでオープンできるファイルタイプの種類と総数を、リアルタイムで把握する必要があるわけです。

    以下が、QuickTime Importerによりオープン可能なファイルタイプの種類と総数を返すnavGetImportTypeList()ルーチンです。仕組みは簡単でして、Importerが取り扱い可能な画像ファイルは、それを処理するためのコンポーネント(システムモジュール)に一対一で対応していますので、それを順次読み出して、そこからファイル情報を得るわけです。

    void navGetImportTypeList( OSType type[],short *nb )
    {
        ComponentDescription    looking;
        Component               cc=0;
        short                   ct=0;
        ComponentDescription    cd;
    
        looking.componentType=GraphicsImporterComponentType; // 対象コンポーネントに
        looking.componentSubType=0;                          // GraphicsImporterを指定
        looking.componentManufacturer=0;
        looking.componentFlags=hasMovieImportMIMEList;
        looking.componentFlagsMask=movieImportSubTypeIsFileExtension|
                                                        hasMovieImportMIMEList;
        while( cc=FindNextComponent( cc,&looking ) )   // コンポーネントを順次得る
        {
            GetComponentInfo( cc,&cd,NULL,NULL,NULL ); // コンポーネントの情報を得る
            type[ct++]=cd.componentSubType;            // OSTypeの配列に代入する
        }
        *nb=ct;                                        // コンポーネント数を返す
    }
    


    何らかの操作(例えばDrag&Drop)で得られたファイルタイプが、Importerでオープン可能な種類かどうかを判断するには、以下のような簡単なルーチンを用意すればOKです。

    short navImportCheckTypeList( OSType type )
    {
        OSType   type1[1000];
        short    i,ct;
    
        navGetImportTypeList( type1,&ct );
        for( i=0;i<ct;i++ )
        {
            if( type==type1[i] )
                return( noErr );
        }
        return( 1 );
    }
    


    おまけとして、「QuickTime Exporter」で取り扱い可能な画像ファイルタイプの一覧を得るためのnavGetExportTypeList()ルーチンを紹介しておきます。
    QuickTime Exporterは、メモリ(CGrafPortやGWorldなど)上に展開した画像データを、指定タイプの画像ファイルとして保存する場合に活用します。

    void navGetExportTypeList( OSType type[],short *nb )
    {
        ComponentDescription    looking;
        Component               cc=0;
        long                    ct=0;
        ComponentDescription    cd;
    
        looking.componentType=GraphicsExporterComponentType; // 対象コンポーネントに
        looking.componentSubType=0;                        // GraphicsExporterを指定
        looking.componentManufacturer=0;
        looking.componentFlags=0;
        looking.componentFlagsMask=0;
        while( cc=FindNextComponent( cc,&looking ) )   // コンポーネントを順次得る
        {
            GetComponentInfo( cc,&cd,NULL,NULL,NULL ); // コンポーネントの情報を得る
            type[ct++]=cd.componentSubType;            // OSTypeの配列に代入する
        }
        *nb=ct;                                        // コンポーネント数を返す
    }
    


    こうして得られたOSTypeの配列を、NavTypeListHandleへ保存するのがnavMakeTypeList()ルーチンです。与えられたファイルタイプの総数から必要とされるメモリ容量を計算し、NewHandleClear()でHandleを確保した後に、ファイルタイプをひとつずつ代入します。ちなみに、NavTypeList構造体はヘッダーファイルのNavigation.hに以下のように定義されています。
    NavTypeListHandleを確保する場合には、OSTypeの配列箇所が総数分増えるとみなし、その容量を計算するわけです。

    struct NavTypeList {
    
        OSType   componentSignature;
        short    reserved;
        short    osTypeCount;
        OSType   osType[1];
    
        };
    
    short navMakeTypeList( short ct,OSType type[],NavTypeListHandle *list )
    {
        short               i,ret=1;
        long                size;
        NavTypeListHandle   lhd;
    
        size=sizeof(NavTypeList)+sizeof(OSType)*(ct-1);      // Handleのサイズ計算
        if( lhd=(NavTypeListHandle)NewHandleClear( size ) )  // Handleを確保する
        {
            (*lhd)->osTypeCount=ct;             // ファイルタイプの総数を代入
            (*lhd)->componentSignature=MY_SIG;
            for( i=0;iosType[i]=type[i];      // 個々のファイルタイプの代入
            ret=noErr
        }
        *list=lhd;
        return( ret );
    }
    


    ここで注意する点は、上記のような操作で得られたNavTypeListHandleをNavGetFile()に渡したとしても、「拡張子」でしかその種類を判断できないファイルには選択表示処理が適応されないということです。本当ならば、「’JPEG’ファイルタイプは表示する!」と設定しさえすれば、Navigation Service側で対応データベースを参照し、ファイルタイプが付加されていないファイルであっても、拡張子が’.jpg’や’.jpeg’のファイルは選択対象だと「賢く判断」してくれるのが人の道でしょう(せめてImporterやExporterが対応しているファイルぐらいは…)。残念ながら、現状のNavigation Serviceはそれほど賢くないため、開発者側で面倒な前処理や後処理を追加する手間が発生してしまいます。

    次回は,今回説明できなかったもうひとつの自作ルーチンnavCheckImportExtention()を紹介し、それをNavGetFile()のフィルター内で使うケースを解説します。また、拡張子もファイルタイプもない画像に遭遇した時、そのファイルがオープン可能かどうかを判断するための簡単な手段も紹介したいと思います。

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

     これまで運用環境について連載で取り上げたことはありましたが、運用をおこなうための実際の手順はまだ解説していませんでしたので、今回は運用手順に注目してみたいと思います。またたんに操作方法を解説するだけではなくなるべくその背景部分についても説明していくことにします。

    インストール

     運用をおこなうには開発をおこなったアプリケーションのインストールをおこなわなければなりません。ここではMac OS XとXcodeを対象に、コマンドライン上でのインストール方法について解説します。
     Xcodeがインストールされた開発環境には、”xcodebuild”というビルドを実行するコマンドが用意されています。このコマンドを用いてXcodeプロジェクトのビルドをおこなえますので、WebObjectsでもこのコマンドを利用することができます。インストールをおこなうには「ターミナル」を起動してプロジェクトが存在するディレクトリに移動し、以下の2つのコマンドを実行してください。なお以下の操作は開発環境上でおこなうものとし、まずは開発環境上でインストールをおこなってから、後で運用環境に転送することとします。

    ・インストールコマンド
    sudo xcodebuild install DSTROOT=/ -buildstyle Deployment
    sudo xcodebuild install DSTROOT=/ -buildstyle WebServer

    ・インストールが成功した場合のメッセージ
    ** BUILD SUCCEEDED **

     sudoコマンド経由での利用となりますので、実行時にはパスワードの入力が求められ、パスワード認証後にビルドが実行されます。インストールが成功しますと上記のメッセージが表示されますが、インストールが確実に成功するように、まずはXcode上でプロジェクトをクリーニングしてからビルドができることを確認しておくのがよいでしょう。
     インストールが成功しますと以下のパスにそれぞれ拡張子”.woa”をもったアプリケーションが作成されます。

    ・デフォルトのインストール先
    /Library/WebObjects/Applications
    /Library/WebServer/Documents/WebObjects

     アプリケーション本体は1つ目のパスにインストールされ、プロジェクト内のWeb Server Resources(正確にはターゲットがWeb Serverのファイル)が2つ目のパスにインストールされます。インストール時にはxcodebuildコマンドを2回実行する必要がありますが、2回目の実行はWeb Server Resourcesをインストールするためです。
     このようにWebObjectsではアプリケーションを2カ所に分けてインストールし、Javaのクラスファイルなどのアプリケーション本体はWebサーバの領域外に配置し、GIF/JPEGファイルなどのリソースファイルはWebサーバの領域内に配置します。

    インストール先の設定

     インストール先はプロジェクトのターゲット設定で変更することができます。プロジェクトをXcodeで開き、左側の「グループとファイル」からプロジェクト名と同じ名前のターゲットを選択します。すると右側にターゲットの設定項目が表示されますので、「設定」->「シンプルビュー」->「インストール先」を選択するとインストール先を変更することができます。

    ・デフォルトのインストール先
    $(LOCAL_LIBRARY_DIR)/WebObjects/Applications

    開発環境から運用環境へ

     通常は開発環境とは別に運用環境用のサーバを用意し、そちらでアプリケーションを稼働させることになりますが、そのためには開発環境上でインストールしたアプリケーションを運用環境に転送する必要があります。
     2カ所にインストールされたアプリケーションをそれぞれ運用環境に転送すればよいのですが、開発環境とは異なったOSで運用をすることも考えられますので、環境にあった方法で転送をおこなってください。例えばApple Remote Desktopを使用して運用環境へアプリケーション一式をコピーすることもできます。なお運用環境へのファイル転送の際には各ファイルのパーミッションなどに注意してください。転送後には運用環境のコマンドライン上でアプリケーションの起動を確認するとよいでしょう。

     開発環境上では正しく動作していたアプリケーションも、運用環境ではうまく動作しない場合もあります。こういった場合にはいくつかの原因が考えられますが、まずはフレームワークやJDBCドライバなどアプリケーション以外に必要なファイルが正しくインストールされているかを確認してください。
     またモデルファイルの接続情報が間違っている場合も考えられます。運用環境上ではEOModelerがインストールされていないとGUI上で接続情報を確認することができませんが、モデルファイルはテキストエディタで直接設定を確認することもできます。モデルファイルはファイルシステム上では実際にはディレクトリですが、モデルファイルのディレクトリ内にある”index.eomodeld”を調べることでJDBCのURLなどの接続情報を確認することができます。

    ・モデルファイル内のJDBCの接続情報
    URL = “jdbc:openbase://127.0.0.1/WOMovies”;

     さて、今回は運用のための手順としてインストール方法を紹介しました。もちろん実際にアプリケーションを運用するためにはあらかじめWebObjectsの運用環境が正しくセットアップされている必要がありますし、インストール後にも様々な設定が必要になってきます。それでは次回も今回に引き続き運用手順について解説してみたいと思います。

    ニュース・解説

    今週の解説担当:木下 誠

    ———————————————————————-
    Apple Remote Desktop 2 のデータベースにアクセスする方法
    ———————————————————————-

    Appleが、Apple Remote Desktop 2 が管理するデータベースにコマンドラインでアクセスする方法や、アプリケーションを作成してアクセスする方法を解説した、「Providing Application Access to SQL Data in Apple Remote Desktop 2」というドキュメントを公開していました。

    Apple Remote Desktop 2 では、クライアントコンピュータの情報を管理するために、PostgreSQLを利用しています。このデータベースに格納されている情報は、Apple Remote Desktop 2に含まれている管理アプリケーションで参照することができますが、一般的なSQLを使ってアクセスすることもできます。このドキュメントでは、SQLアクセスを可能にするためのPostgreSQLの設定の変更、およびpsqlコマンドを使ったデータベースへのアクセス方法を紹介しています。

    また、管理専用アプリケーションを作る例として、REALBasicを使ったデータベースへの接続を紹介しています。REALBasicはPostgreSQLへアクセスするためのデータベース・プラグインを含んでいるため、簡単に利用することができます。
    Apple Remote Descktop 2を使って管理をしている方、またはPostgreSQLでデータベースを構築し管理アプリケーションを作ろうと思っている方に、参考になる記事でした。

    Providing Application Access to SQL Data in Apple Remote Desktop 2
    http://developer.apple.com/appleapplications/ardsql.html

    ———————————————————————-
    JavaアプリケーションからHelp Viewerを呼び出すサンプル
    ———————————————————————-

    JavaアプリケーションからApple Help Viewerを動作させるサンプル、「HelpHook」が公開されています。実際は、JNIを使って、JavaアプリケーションからCのフック関数を経由し、Cocoa APIを呼び出すサンプルになっています。

    Sample Code:
    HelpHook
    http://developer.apple.com/samplecode/HelpHook/HelpHook.html

    ———————————————————————-
    Sequence Grabberを使ってビデオをキャプチャするサンプル
    ———————————————————————-

    Sequence Grabberを使ってビデオをキャプチャするサンプル、「BrideOfMungGrab」が公開されています。このサンプルは、SGDataProcSampleをベースにした一連のサンプル、Minimung、MungGrab、SonOfMungGrab、の最新作だそうです。

    今回は、ビデオの上に文字を書いているのですが、GWorldの使用をやめてCoreGraphicsを使っているそうです。

    Sample Code:
    BrideOfMungGrab
    http://developer.apple.com/samplecode/BrideOfMungGrab/BrideOfMungGrab.html

    ———————————————————————-
    Sequence Grabberでキャプチャするときのファイルサイズ
    ———————————————————————-

    もう1つ、Sequence Grabber関係があります。Sequence Grabberを利用してビデオをキャプチャする際に、QuickTimeはあらかじめ巨大なファイルを確保します。これを避ける方法を説明したTechnical Q&A、「Sequence Grabber preallocates large file when recording」が公開されています。

    SGSetOutputMaximumOffsetを使うことで、出力されるデータのサイズを制御することができます。他にも、データを格納する際に有用なAPIが紹介されています。

    Technical Q&A QA1411:
    Sequence Grabber preallocates large file when recording
    http://developer.apple.com/qa/qa2005/qa1411.html

    ———————————————————————-
    QuickTimeのNativePathNameToFSSpecの問題
    ———————————————————————-

    QuickTimeのNativePathNameToFSSpecを呼んだときに、bdNameErrが返る問題を解説したTechnical Q&A、「NativePathNameToFSSpec returns bdNameErr (-37) error」が公開されています。

    現在のバージョンのQuickTimeでは、ファイル名+拡張子が63文字を超えるファイルは取り扱えないそうです。いささか、恥ずかしい問題だと思います。

    Technical Q&A QA1413:
    NativePathNameToFSSpec returns bdNameErr (-37) error
    http://developer.apple.com/qa/qa2005/qa1413.html

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

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