MOSA Multi-OS Software Artists

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

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

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

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

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

    2004-06-22

    目次

    • Cocoaでいこう! Macらしく  最終回  Yoshiki(DreamField)
    • 小池邦人の「Carbon API 徒然草
    • 「Behind the WebObjects」  第22回  田畑 英和

    Cocoaでいこう! Macらしく  最終回 Yoshiki(DreamField)

     ついに今回で終わりです。1年と2ヶ月の間、ご愛読ありがとうございました。

    座標の原点を左上にしよう(再び)

     今回は、第38回で行ったimageViewをflipさせるのとは違う方法で、画像表示の原点を左上にします。
     NSScrollViewの挙動が左上原点に変わるのは、そのsubviewがflipしているからです。そこで、NSScrollViewとimageViewの間にもう一つNSViewクラスのインスタンスを挟み、これをflipさせてしまいます。こうすれば、imageViewはそのままで、NSScrollViewの挙動を変えることができます。では、そのクラスを実装しましょう。名前はFlippedviewにします。新規ファイルを作る時の雛形は、Objective-C NSView subclassを選んで下さい。ファイルを作ったら、雛形で用意されているメソッドはそのままほっておいて、次のメソッドを実装してください。

    - (BOOL)isFlipped {
        return YES;
    }
    


     あまりにシンプルですが、このクラスは実際に描画を行うわけでは無いので、これだけです。では、このクラスのインスタンスをnibファイルに加えましょう。MyDocument.nibを開いてください。XcodeからFlippedView.hを、nibファイルウィンドウにドラッグ&ドロップします。この辺りの操作は、もうお馴染みですね。MyImageViewを選んでinfoパネルを開いてください。選びにくいようでしたら、nibファイルウィンドウを一覧表示にして選ぶという方法もあります(fig.01)。確実に選ばれているかどうかは、infoパネルのタイトルバーを見れば分かります(fig.02)。選んだら、現在はCustom ClassがMyImageViewになっているはずですので、これを先ほど読み込んだFlippedViewに変更します(fig.03)。次に、新しくCustomViewをFlippedViewの中に加えます(fig.04)。加えたら、左下の座標が(0,0)になるように、ぴったり合わせてください(fig.05)。サイズはプログラムの中から変更しますので、適当でかまいません。位置を合わせたら、このCustomViewのCustom ClassをMyImageViewに変更しましょう(きちんと選ばれていることを確認してから変更してください)。これでNSScrollViewの中にFlippedView、そしてさらにその中にMyImageViewという構造になりました(fig.06)。構造的にはこれで良いのですが、今までMyImageViewだったオブジェクトをFlippedviewにしてしまったので、Outletの接続先も変える必要があります。File’s Ownerを選んでinfoパネルをConnectionsに切り替えてください。imageViewの接続先がFlippedViewになってしまっているので、これを外します(fig.07)。そして、改めてMyImageViewに接続し直してください(fig.08)。以上でnibファイルの加工は終わりですので、保存してXcodeに戻りましょう。

    [fig.01] 一覧表示からなら確実にオブジェクトを選択できる
    http://www.remus.dti.ne.jp/~yoshiki/cocoa/ed1/55/images/fig01.gif

    [fig.02] infoパネルのタイトルバーには選ばれているオブジェクトが表示される
    http://www.remus.dti.ne.jp/~yoshiki/cocoa/ed1/55/images/fig02.gif

    [fig.03] MyImageViewからFlippedViewに変更する
    http://www.remus.dti.ne.jp/~yoshiki/cocoa/ed1/55/images/fig03.gif

    [fig.04] FlippedViewの中にCustomViewをドラッグ&ドロップ
    http://www.remus.dti.ne.jp/~yoshiki/cocoa/ed1/55/images/fig04.jpg

    [fig.05] 左下に合わせる
    http://www.remus.dti.ne.jp/~yoshiki/cocoa/ed1/55/images/fig05.jpg

    [fig.06] 間にFlippedViewを挟むことができた
    http://www.remus.dti.ne.jp/~yoshiki/cocoa/ed1/55/images/fig06.gif

    [fig.07] imageViewの接続先がFlippedViewになっているので外す
    http://www.remus.dti.ne.jp/~yoshiki/cocoa/ed1/55/images/fig07.gif

    [fig.08] imageViewをMyImageViewに接続する
    http://www.remus.dti.ne.jp/~yoshiki/cocoa/ed1/55/images/fig08.gif

     あと一つ実装しなければならないことが残っています。MyImageViewは必要に応じて自分自身のサイズを調節していますが、FlippedViewは何もしていません。MyImageViewはFlippedViewの中に表示されるのですから、これでは困ります。二つは常に同じサイズでなければなりません。そこで、MyImageViewが自分自身のサイズを調節する時に、いっしょにFlippedViewのサイズも調節することにします。MyImageViewが自分自身のサイズを調節している箇所は二つです。これに下記の様に、FlippedViewの調節を加えます。

    - (void)setImage:(NSImage *)newImage{
        [ newImage retain];
        [ image release];
        image = newImage;
        [ self setFrameSize: [ image size]];
        [ [ self superview] setFrameSize: [ image size]];
    }
    
    - (void)setZoomValue:(float)newZoomValue {
        NSRect theRect;
    
        zoomValue = newZoomValue;
        theRect.size = [ image size];
        theRect.size.width *= zoomValue;
        theRect.size.height *= zoomValue;
        theRect.origin = NSZeroPoint;
        [ self setFrame:theRect];
        [ [ self superview] setFrame:theRect];
        [ self setNeedsDisplay:YES];
    }
    


     それぞれ、[ self superview]にメッセージを投げている所が、加えた部分です。FlippedViewは、imageViewのsuperviewですから、これでメッセージが届きます。それでは、ビルドして実行してみてください。ウィンドウのサイズを変更すると、表示の起点が左上になっていることが分かります(fig.09)。これでまた一つMacらしくなりましたね。もっとも、拡大/縮小後のウィンドウの位置は、まだまだMacらしくありませんが、これの調節まで書いていると終わらないので、これは各自で工夫してみて下さい。

    [fig.09] 左上が起点なので、ウィンドウのリサイズは表示範囲の変更に見える
    http://www.remus.dti.ne.jp/~yoshiki/cocoa/ed1/55/images/fig09.jpg
    (サンプル画像は、ゆきみだいふくさんのご好意により、使用させていただいています。)

    メニューにチェックを付けよう

     実は、もう一つ気になっていることがあります。現在のViewメニューは、一目でどのモードが選ばれているのか分かりません。通常のMacのアプリでしたら、今選ばれているモードのメニューにチェックを付ける等して、明示するはずです。では、これをどこで行えば良いでしょうか。まっ先に思いつくのは、メニューでモードを選んだ時です。この時、チェックしなければならないメニューは変化します。では、他には無いでしょうか。TinyViewは、同時に複数のウィンドウを開けます。ウィンドウ毎にモードを切り替えますから、それぞれのウィンドウでモードが違うこともあるはずです。従いまして、メインウィンドウが切り替わった時に、チェックを付けるメニューもそれに合わせて変更する必要があります。そして全てのウィンドウを閉じた時は、全てのチェックを外す必要もあるでしょう。以上のことを実装します。まずは現在のモードを覚えておく必要がありますので、MyDocumentクラスに下記のインスタンス変数を加えてください。

    int zoomMode;

     この値をメニューを切り替えた時にセットします。selectZoomMenu:の頭の方を次の様に書き換えて下さい。

    - (IBAction)selectZoomMenu:(id)sender{
        float theZoomValue;
    
        zoomMode = [ sender tag];
        switch( zoomMode){
            ・
            ・
    


     これだけでは、一度もメニューを選んで無い時の値が0になってしまいます。これを1にするために、initに次の一行を加えます。

    zoomMode = 1;

     これでモードを覚えておく事ができるようになりましたので、このモードに合わせてメニューを切り替えるメソッドを実装しましょう。
    MyDocumentControllerに次のメソッドを実装して下さい。

    - (void)updateViewMenuWithMode:(int)newMode{
        NSMenu *theViewMenu;
        int i;
    
        theViewMenu = [ [ [ NSApp mainMenu] itemWithTitle:NSLocalizedString(@"View", nil)]
     submenu];
        for( i = 0; i <= 2; i++){
            [ [ theViewMenu itemWithTag:i] setState:(i == newMode)?( NSOnState):
    ( NSOffState)];
        }
    }
    


     ここでは、指定されたモードと同じメニューだけstateをOnにし、それ以外をOffにしています。何でMyDocumentControllerの方に実装するかと言うと、今回の場合はMyDocumentクラスのインスタンスが一つも無くなった時にも呼び出されるからです。その処理は同じMyDocumentControllerにありますから、先に実装してしまいましょう。removeDocument:メソッドでドキュメントが一つも無くなった時の処理の最後に、次の一行を加えて下さい。

    [ self updateViewMenuWithMode:-1];

     -1なんてモードはありませんから、これでチェックが全部外れます。次に、MyDocumentの方では、zoomModeをパラメタとしてメッセージを投げるメソッドを実装します。

    - (void)updateViewMenu{
        [ [ NSDocumentController sharedDocumentController] updateViewMenuWithMode:zoomMode];
    }

     これを必要な所で呼び出せば良いわけです。selectZoomMenu:と、windowDidBecomeMain:の両方の最後に、次の行を加えてください。

    [ self updateViewMenu];

     以上です。このままですとワーニングが出ますので、適宜ヘッダーの宣言を追加し、新たに必要になったヘッダーはimportするようにしてください。ワーニングが出たままでも実行はできますが、なるべく潰した方がミスを発見しやすくなります。それでは実行してみましょう。複数の画像を開いて拡大/縮小を行い、メニューがどう変化するかを見てください。期待通りの動作になったと思います(fig.10)。

    [fig.10] メニューにチェックが入るようになった
    http://www.remus.dti.ne.jp/~yoshiki/cocoa/ed1/55/images/fig10.gif

     予定した内容が収まりきらず、最後は駆け足になってしまいました。これでも普段の倍の量なのですが。申し訳ない。

    最後に

     ここまでお付き合いくださいまして、ありがとうございます。なるべく市販の本に無いことを書きたいと思うあまり、構成的には少し歪んでしまったと、ちょっと反省もしています。ですが、本だけではなかなか理解しにくい所や、本では説明してくれない所を、私なりの考えを交えて説明してきたつもりです。まだまだ説明していないことは一杯ありますが、これ以上はご自分で本を読まれたり、ドキュメントを調べたりすれば、十分に解決できるでしょう。
    Cocoaはとても強力なフレームワークであり、Objective-Cはとても素晴らしいオブジェクト指向言語です。本連載を通して、少しでもCocoaやObjective-Cを面白いと思っていただけたら、幸いです。長い間、ありがとうございました。

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

    Main Event Loopへ入る前準備-その1

    今回と次回は、サンプルアプリケーションに実装されているCarbon Event TimerとCarbon Event Handlerの話をします。具体的には、初期化ルーチンのstartApplication()から呼ばれている、setupEventLoopTimer()とsetupApplicationEvent()についての解説となります。

    Carbon Event Timerとは、「アプリケーション起動中に定期的に実行しなければいけない処理」を受け持つルーチンのことです。アプリケーションの種類によっては、状況に応じて、こうした処理が複数存在したりします。
    setupEventLoopTimer()は、サンプルアプリケーションに、このCarbon Event Timerルーチンを実装しています。WaitNextEvent()を呼ぶことで、自分自身でMain Event Loopを管理していた時代には、こうしたルーチンはループ内から直接呼べばOKでした。Thread ManagerのAPIを使うという手もありましたが、こちらの方が簡単な実装方法です。まずは、Mac OS 9時代のアプリケーションで用いていた、古典的なMain Event Loopルーチンを見てみましょう。

    void mainEventLoop(void)
    {
        EventRecord        event;       //  どんなイベントが発生したかを保持する
        short              flag;
    
        FlushEvents( everyEvent,0L );   //  まずは待ちイベントをすべてクリアする
        while( 1 )
        {
            myEventLoopTimer();         //  定期的に実行しなければいけない処理
    
            if( WaitNextEvent( everyEvent,&event,10L,0L ) ) //イベントを受け取る
            {
                switch( event.what )
                {
                    case mouseDown:    //  マウスが押された
    
                        doMouseDown( &event );
                        break;
    
                    case keyDown:     //  キー入力がなされた
                    case autoKey:
    
                        doKeyDown( &event );
                        break;
    
                    case updateEvt:    //  ウィンドウの書き換えが必要になった
    
                        doUpdate( (WindowRef)event.message );
                        break;
    
                    case activateEvt:  //   ウィンドウのレイアが切り替わった
    
                        flag=event.modifiers&activeFlag;
                        doActivate( (WindowRef)event.message,flag );
                        break;
                }
            }
        }
    }
    


    mainEventLoop()ルーチンから呼ばれているmyEventLoopTimer()には、定期的に実行する処理が記述されています。どんな状況(あるウィンドウがフロントの時だけ...)において、どんなタイミング(間隔)で呼び出すかについては、すべて自分自身で管理する必要があります。また、Mac OS 9の仕組み上、ユーザがメニューやウィンドウをドラッグしている最中などは、mainEventLoop()へと制御が渡って来ませんので、myEventLoopTimer()も実行されなくなるという大きな制限が存在していました。

    それとは異なり、モダンなCarbonアプリケーションでMain Event Loopへ入るためには、RunApplicationEventLoop()を実行します(抜けるにはQuitApplicationEventLoop()を実行)。サンプルでは、startApplication()の最後でRunApplicationEventLoop()を呼んでおり、この時点でMain Event Loopが開始されるわけです。CarbonアプリケーションのMain Event Loopはシステム側で管理されており、そこで受けたCarbon Eventは種類により振り分けられ、適切なクラスのCarbon Event Handlerルーチンへと渡される仕組みになっています。

    つまり、Carbonアプリケーションでは、mainEventLoop()を記述する必要がない代わりに、myEventLoopTimer()を呼び出す場所もなくなってしまったわけです。そこで、Carbon Eventの登場と同時に、Carbon Event Timerの仕組みが導入されました。この仕組みは、簡単にCooperative(協調的)な別スレッドを作る仕組みだと考えれば分かりやすいと思います。協調的スレッドですが、Mac OS 9の時とは異なり、メニューやウィンドウのドラッグ中にもちゃんと処理が継続されます(逆にそのために注意すべき点もある)。

    こうしたCarbon Event Timerルーチンは、InstallEventLoopTimer()によってアプリケーションに実装します。以下がCrbon Event TimerのmyEventLoopTimer()ルーチンを実装しているsetupEventLoopTimer()です。

    void setupEventLoopTimer(void)
    {
        InstallEventLoopTimer( GetCurrentEventLoop(),0.0,0.1,myEventLoopTimer,
                                                                  NULL,NULL );
    }
    


    InstallEventLoopTimer()の最初の引数はEventLoopRefで、どのEvent Loopに対応しているのかを指示しています。GetCurrentEventLoop()により得たEventLoopRefを渡すことで、現在働いているEvent Loopに実装するよう指示しています。次の引数は開始時間、その次は呼び出し間隔で、それぞれ秒で指定します。4番目の引数にはCarbon Event Timerルーチン本体を渡します。これにより、myEventLoopTimer()は、Main Event Loopが始まると同時に有効となり、アプリケーションが起動している間、0.1秒間隔で呼び出されるわけです。

    pascal void myEventLoopTimer( EventLoopTimerRef timeref,void *userData )
    {
        WindowRef    wptr;
        CGrafPtr     cptr;
        Rect         brt;
        short        chk;
        Point        pt;
    
        wptr=FrontNonFloatingWindow();  // フロントウィンドウのWindowRefを得る
        if( wptr && menu_track==0 )   // ウィンドウなしとメニュー表示中は避ける
        {
            chk=QDSwapPort( GetWindowPort( wptr ),&cptr ); // カレントポート待避
            GetMouse( &pt );                   // マウス位置を得る
            GetWindowPortBounds( wptr,&brt );  // ウィンドウの矩形領域を得る
            switch( GetWRefCon( wptr ) )       // ウィンドウの種類をチェック
            {
                case 'VIEW':                   // これは「画像ウィンドウ」
    
                    brt.right-=15;             // スクロールバー部分を外す
                    brt.bottom-=15;
                    if( PtInRect( pt,&brt ) )  // ウィンドウ領域内か判断
                        myCursor( 128 );       // ハンドカーソル表示
                    else
                        myCursor( 0 );        // 矢印カーソル表示
                    break;
    
                default:                       // その他のウィンドウ
    
                    myCursor( 0 );             // 矢印カーソル表示
                    break;
            }
            if( chk )
                QDSwapPort( cptr,NULL );       // カレントポート復帰
        }
        else
            myCursor( 0 );                   // 矢印カーソル表示
    }
    


    ここでの処理は、表示されているウィンドウの種類に応じマウスカーソルの形状を変えるという簡単なものです。しかし、アプリケーションの種類によっては、このルーチン内で特別な処理を実行する必要が出てきます。例えば、QuickTimeのMovie Controller(Movieを操作するためのコントロール)を利用している場合には、処理時間を配分するためにMCIdle()を定期的に呼ぶ必要があります。同様に、QuickTimeのSequence Grabberでビデオ映像を表示している時には、定期的にSGIdle()を呼ぶことになります。こうした「定期的に実行しなければいけない約束事」は、Event Loop Timer内で実行してやるのが一番効率的です。Mac OS Xになってから、こうした手間のかかる「約束事」は随分と少なくなりましたが、まだいくつか存在していますので注意が必要です(化石のようなもの)。

    RunApplicationEventLoop()やQuitApplicationEventLoop()が定義されているヘッダファイルはCarbonEvents.hです。InstallEventLoopTimer()の方はCarbonEventsCore.hに定義されていますので参照してみてください。次回は今回の続きで、アプリケーション自身に実装するCarbon Event Handlerの話です。

    つづく

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

     前回はProject WONDER(1.0.1)のCommonディレクトリの構成について解説しましたが、今回はそれ以外のディレクトリについて説明します。

    Adaptors

     もともとソースコードが公開されているWebサーバアダプターの改良版です。アップルからバイナリーが提供されていないプラットフォーム向けの、ビルド済みアダプターの配布がおこなわれています。具体的には以下のOS向けに各種アダプターが提供されています。

    HP-UX : Apache
    Red Hat Linux : CGI, Apache
    FreeBSD : CGI, Apache
    OpenBSD : CGI, FastCGI, Apache

    ・アダプターダウンロードページ
    http://wonder.sourceforge.net/WOAdaptor.html

     またビルド済みアダプターの提供だけではなく、以下のようなコードの修正や機能的な改良もおこなわれています。

    ・アプリケーション数の上限値の変更(16 -> 64)
    ・Apacheアダプターでのタイムアウトの修正
    ・ビルドスクリプトのLinux対応
    ・Apacheアダプターでのリクエストヘッダーの追加

    DynaReporting

     グルーピングしたレコードのレポートを作成するフレームワークです。このフレームワークはDRGroupingとWRReportingの2つから構成されており、サンプルプロジェクトも付属しています。

    Experimental

     以下の実験的なプロジェクトが収められています。

    ・DevStudio
     Webベースの開発環境です。Direct To WebのルールやEOFのモデルファイルをサポートしています。

    ・DAPDB_PlugIns
     SAP DBのためのデータベースプラグインです。Project WONDERでは基本的にはBSDスタイルのライセンスを採用していますが、このプラグインはLGPLを採用しています。またこのプラグインを使用するにはSAP DBのためのJDBCドライバーが別途必要になります。
     なおSAP DBは現在MaxDBへと名称を変更しており、MySQLの開発をおこなっているMySQL ABへと引き継がれています。

    「SAP DB」
    http://www.sapdb.org/

    ・WOWebLog
     ブックマーク可能なステートレスのWebLogアプリケーションです。このアプリケーションは様々なフレームワークから構成されており、Seppukuという名前のフレームワークも含まれています。
     このフレームワークは、以前はWOHarakiriと呼ばれていたものの改良版であり、反応のなくなったアプリケーションを自動的に終了してくれます。
     WOHarakiriではアプリケーション側でのコード追加による対応が必要でしたが、改良版であるSeppukuではNotificationを利用することにより、アプリケーション側での対応が必要なくなり、フレームワークを追加するだけで利用できるようになりました。

    PayPal

     WebObjectsアプリケーションからPayPalの送金サービスを利用できるようにするフレームワークです。実際に利用するにはPayPalの口座が必要になります。

    ・PayPal
    http://www.paypal.com/

    SVGObjects

     動的にSVGフォーマットのデータを作成します。複数のサンプルも付属しており、SVGの統合についてはRavi Mendis著「WebObjects Developer's Guide」で詳しく解説されています。

    「WebObjects Developer's Guide」
    http://www.amazon.co.jp/exec/obidos/ASIN/0672323265/

    Utilities

     ユーティリティが収められており、Project Builderのメニューをアップルスクリプト対応にするプラグイン「BXAppleScriptMenuPlugin」や、参照しているフレームワークをアプリケーション内(.woa内)にコピーするPerlのスクリプト「woaFrameworkMerger」や、Webセーフカラーに対応したMac OS X用カラーパレット「HTMLColorPalette」などが含まれています。

    Validity

     EOFのためのルールベースのValidation(データの正当性検証)システムです。Validationのルールを設定するアプリケーション(ValidityModeler)も付属しており、アトリビュートあるいはリレーションごとにValidationルールを設定することができます。

    以上のようにProject WONDERには様々なフレームワーク/アプリケーションなどが収められています。これらはオープンソースとして開発が進められており、最新版のVer2.0では様々な改良、機能追加がおこなわれています。そこで次回は最新版のVer2.0について紹介する予定です。

    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=モサ伝]第117号

    2004-06-15

    目次

    • Cocoaでいこう! Macらしく  第54回  Yoshiki(DreamField)
    • 藤本裕之のプログラミング夜話 #47
    • 高橋真人の「プログラミング指南」 第46回
    • ニュース・解説

    Cocoaでいこう! Macらしく  第54回 Yoshiki(DreamField)

     この連載も今回を含めて残す所あと2回です。

    画像を拡大するモードを付けよう(その4)

     前回積み残したWindowの最大のサイズの調節を行います。実はこのロジックは、最初に画像を開く部分で既に実装していました。MyDocument.mの次のメソッドです。

    - (void)windowControllerDidLoadNib:(NSWindowController *) aController{
        NSWindow *theWindow;
        NSSize theScrollViewSize;
        NSRect theScrollViewRect, theWindowMaxRect;
    
        [super windowControllerDidLoadNib:aController];
        [ imageView setImage:image];
        [ image release];
        theWindow = [ aController window];
        theScrollViewSize = [ NSScrollView frameSizeForContentSize:[ imageView frame].size
     hasHorizontalScroller:[ scrollView hasHorizontalScroller] hasVerticalScroller:
    [ scrollView hasVerticalScroller] borderType:[ scrollView borderType]];
        [ theWindow setContentSize:theScrollViewSize];
        theScrollViewRect.origin = NSZeroPoint;
        theScrollViewRect.size = theScrollViewSize;
        theWindowMaxRect = [ NSWindow frameRectForContentRect:theScrollViewRect 
    styleMask:[ theWindow styleMask]];
        [ theWindow setMaxSize:theWindowMaxRect.size];
        [NSTimer scheduledTimerWithTimeInterval:0 target:self selector:
    @selector( timerAdjustWindowSize:) userInfo:theWindow repeats:NO];
    }
    


    theWindowの取得からNSTimerの手前の部分までがそうですね。これを切り出してしまいましょう。

    - (void)adjustWindow{
        NSWindow *theWindow;
        NSSize theScrollViewSize;
        NSRect theScrollViewRect, theWindowMaxRect;
    
        theWindow = [ scrollView window];
        theScrollViewSize = [ NSScrollView frameSizeForContentSize:[ imageView frame].size
     hasHorizontalScroller:[ scrollView hasHorizontalScroller] hasVerticalScroller:
    [ scrollView hasVerticalScroller] borderType:[ scrollView borderType]];
        [ theWindow setContentSize:theScrollViewSize];
        theScrollViewRect.origin = NSZeroPoint;
        theScrollViewRect.size = theScrollViewSize;
        theWindowMaxRect = [ NSWindow frameRectForContentRect:theScrollViewRect 
    styleMask:[ theWindow styleMask]];
        [ theWindow setMaxSize:theWindowMaxRect.size];
    }
    


     一カ所だけ変えています。theWindowをaControllerから取得していましたが、このメソッドにaControllerは無いので、scrollViewから取得しています。では、元々このロジックがあった場所は、このメソッドを呼び出すようにしましょう。

    - (void)windowControllerDidLoadNib:(NSWindowController *) aController{
        NSWindow *theWindow;
    
        [super windowControllerDidLoadNib:aController];
        [ imageView setImage:image];
        [ image release];
        theWindow = [ aController window];
        [ self adjustWindow];
        [NSTimer scheduledTimerWithTimeInterval:0 target:self 
    selector:@selector( timerAdjustWindowSize:) userInfo:theWindow repeats:NO];
    }

     adjustWindowがこのメソッドよりも後に書いてある場合はワーニングが出ますから、ヘッダーで宣言してください。さらに、zoomValueを変更した直後にもこれを加えます。

    - (IBAction)selectZoomMenu:(id)sender{
        float theZoomValue;
    
        switch( [ sender tag]){
        case 0:
            theZoomValue = 0.5;
            break;
        case 1:
            theZoomValue = 1.0;
            break;
        case 2:
            theZoomValue = 2.0;
            break;
        default:
            return;
        }
        [ imageView setZoomValue:theZoomValue];
        [ self adjustWindow];
    }
    


     これでimageView自身がサイズを調節した直後に、ウィンドウのサイズを調節するようになりました。ビルドして実行してみてください。「×0.5」の時にはウィンドウは自動的に縮みますし、「×2」の時は、自動的にはウィンドウのサイズは広がりませんが、画像の表示サイズ一杯まで拡げられるようになっているはずです。これで画像を拡大縮小するモードは実装できました。

    ところで今回、ウィンドウのサイズの調節は、MyDocumentクラスの方で行うようにしましたが、これはやろうと思えばimageViewの方に組み込んでしまうことも可能です。必要なのはwindowとscrollViewとimageViewのframeサイズですから、windowは[ self window]で取得できますし、frameも[ self frame]で取得できます。scrollViewに関しては、IBOutletで接続しても良いですし、[self superview]で取得することも可能でしょう。こうやってimageViewの方に組み込んでしまえば、MyDocumentは何も考える必要がなくなります。では、どちらに組み込む方が正しいのでしょうか。残念ながら、これには明確な答えはありません。何故なら、これは設計思想の問題だからです。オブジェクト指向というのは、誰が何を知っていて、何をやってくれるのか、何に対して責任を持っているのか、これを考えて実装して行くものだと、私は思っています。今回の場合も、これをどう考えるのかで決まります。現在のTinyViewでは、どちらで実装しても問題は起こりませんが、例えば将来ウィンドウにボタンやスライダー等、何かを付加した場合、その部分に対してimageViewは責任を持てないでしょう。そう考えて、ウィンドウの調節はMyDocumentの方で責任を持つことにしました。ただし、これはあくまで現段階における私個人の考えですので、これが正しいという物ではありません。重要なのは、こういう考え方を持つということです。
     さて、これで一通りの実装は終わりましたが、まだ気になる所が残っています。それは、またしても画像表示の原点が左下になってしまったということです。第38回で説明したように、Macだったらこれは左上であるべきでしょう。ですが第52回で書いたように、現在の実装ではimageViewをflipさせたくありません。そこで次回は、第38回で説明したimageViewをflipさせる方法とは、ちょっとだけ違うやり方でこれを何とかします。

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

     こないだ鎌倉清酒研究会という団体の酒飲み会でヨシキ君(このモサ伝にCocoaの連載を書いているヒト)と会い、そんときに彼が「ボクはSEです」と言うのでへぇと思った。というのは(これもごく最近知ったんだが)彼はオレと同じ歳で、大体オレの年代で零細企業勤務経験豊富なプログラマというのは「SE」という用語が嫌いだからである。

    巷間流布しているSE、システムエンジニアのイメージというのは大体「顧客の希望、要求を分析し、システムを設計して開発作業のディレクションを行う」というあたりだろう。映画監督と俳優が別の職業であるように、SEとプログラマも違う仕事、別の職業である。両者の間に上も下もない、はずである。
     ところが一般には「プログラマの偉いのがSE」とか「プログラマからSEに出世する」というような「プログラマよりSEの方が上」という「常識」がある。「分析・設計ができて初めてSE、プログラムが組めるだけではプログラマどまり」というような言も見たことがある。これが気に入らない。まぁそれでも第三者がそう認識しているだけならいいが、最近は「最初からSEという肩書きで採用された若いのがその肩書き故にプログラマを見下す傾向」まである。アホかっつの。

    上にあげた「理想的なSE像」に沿えば、SEというのは顧客が満足し納期も守れるようなシステムの仕様を決め設計を行うことになっている。プログラマはその仕様を実現すべく、その設計に沿って開発作業を行う。
     で、あるから、仕様が馬鹿げていたり設計に無理があった場合、それは全部プログラマの作業にしわ寄せが来る。駆け出しのプログラマならいざ知らず、ちょっと年期の入ったプログラマになればそういうことはすぐ分かる。
     やんわりと指摘して(しないと死活問題だからね)修正されればいいんだが、前述のごとく、時として自分が「SEなんだからプログラマより偉い」「ボクは大企業に採用されたのだ下請けなんかより上等な人間だ」と盲目的に思っているバカがいて「外注プログラマごときに指摘されるようなミスをボクが犯すはずはない」とばかり意地になる……。そんな馬鹿なって思うだろうが沢山いるんだよ、そういうのが……。
     かくして使えるヴェテランは逃げてしまい(カチカチ山のタヌキぢゃあるまいし沈む泥船に最後までつきあう謂れはない)、プロジェクトはデスマーチを奏でつつ泥沼の中の行進を続けるわけ。……それでも1,2年経つとそういうバカが昇進してたりするから企業社会というのは不可思議というか謎に満ちているというか……。

     とまれ、プログラマたちがこういうSEを嫌うのは「仕事がうまく行かないから」でも「うまく行かないことを自分のせいにされる」からでもない。自分のせいにされるまでそんな仕事に関わってること自体自分のミスだ。そうではなくて「論理的な思考能力のないヤツと仕事をするのがジンマシンが出るほど嫌だから」である。
     橋本治はかつて「正当性というのは論理によってのみ勝ち取れるものだ」と言った。「SEだからプログラマより優れている」という論理は存在しないし「大企業の社員は中小企業の社員、あるいはフリーランスより人間として上だ」という論理もない。これが真だというのなら論理で証明しなければならない。証明できないことを頭から信じて疑わないだけでなく、他人にもそれが通用すると思ってるニンゲンと仕事なんか出来ない。そんなヤツ、マシンに向かって念じればバグが取れるというのと五十歩百歩ではないか。
     で、ヨシキ君は今までそういうSEに遭った(この字を使いたい)ことがないんだな、幸せな人生を歩んで来たヒトなんだな、と思ったわけなんである。いや皮肉ぢゃなくね(笑)。

    出典は覚えていないがどっかでこういうジョークを見たことがある(細部はうろ覚え)。「プログラマに必要な能力は『交渉・企画・分析・設計・開発・保守・サポート・工程管理』、SEに必要な能力はこれから『開発・保守・サポート』を抜いたもの、マネージャーはさらに『分析と設計』を抜き、営業になると『企画と工程管理』の能力も要らない」。ご参考まで。

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

    番外編

     こんにちは、高橋真人です。
     今回は、ちょっと話題から外れるのですが、前回の記事の中で触れた「ヘッダファイルを開く」という件に関してお話ししてみたいと思います。
     Mac OS Xは、UNIX系のOSということになっていますから、たとえばCの入門の第一歩としておなじみの”HelloWorld”なども、プログラミング入門書に記載されている例の通りに動作します。もちろん、Windows向けの本ではダメですが。
     ターミナルから「cc hello.c」などと打ち込んで、a.outなる実行ファイルが生成されるところなど、Cを学んだ時に本の説明と目の前のThink Cのギャップにしばし言葉を失った身としては、感慨深いものがあります。
     とはいえ、Mac OS XはMac OSでもあるわけですから、UNIXであるということをほとんど意識しないで開発が行えるのも事実。長年プログラミングをやってきていても、正規表現だとかシェルスクリプトだとかのUNIXを背景にして生まれてきた技術にはほとんど縁を持っていないということも、Macの世界では珍しいことではないようです。そんな方にとっては前回のような

    /usr/include/gcc/darwin/…

    などというパスを示されても「さて、どうやって開いたものやら」となるのかもしれません。
     Finderから起動ディスクの中身を覗いても、そこにはSystem、Library、Usersだとかの名前ばかりで、usrなどというフォルダはどこにも見えません。usrというのを「Usersのことだろう」と勝手に解釈して中を探ってみても、当然中には個々のユーザーのホームフォルダがあるだけです。
     UNIXも歴史のあるOSですから、ディレクトリ構造に関してはある程度標準的なものがあるようなので、興味のある方は本などを読んで勉強してみることをお勧めします。
     さて、今回話題になっているusrディレクトリは通常ユーザーからは見えないようになっています。いちばん明快なのはターミナルを立ち上げて、

    ls -l /

    と打ち込んでみることです。(もちろん末尾にはリターンを打ってください)
     / というのは、UNIXではルートディレクトリ、つまりディレクトリ階層の根幹を表します(読み方も「ルート」です)。
     さて、上記のように打ってみると、Finderで起動ディスクのウインドウを開いた時には見えなかったものがいくつかあるのに気づきます。もちろん今回話題にしているusrもありますね。
     ターミナルの使い方について説明している余裕もないので、詳しいことは本でも読んで勉強していただくことにしますが、今回のテーマであるヘッダファイルの中身を見る方法として、まず最初に考えられる方法がUNIXのコマンドを組み合わせる方法です。
     ファイルの中身を表示するコマンドはいくつかありますが、今回のようなケースでお勧めなのはlessというコマンドです。
     ターミナルを立ち上げたら、

    less /usr/include/gcc/darwin/3.3/c++/iostream

    と打ち込めば、iostreamの中を見ることができます。
     lessというのはページャと呼ばれるコマンドの一種で、ページ単位で内容を表示する目的に使われるコマンドですが、多くの場合「ls -l | less」などと、他のコマンドの出力を受け取ってページ単位で表示する用途に使われます(moreというコマンドも同じ目的で使われる)。
     これも詳しくはmanコマンドを使うなり、書籍で調べるなりしていただきたいのですが、最低限の操作方法を示しておきます。ファイルの内容が表示されたら、前進するときはスペース、後退する時には「b」です。これでファイルの中を移動してください。終了は「q」です。

    次に、同じくターミナルを使うものの、手慣れたアプリケーションを使う方法です。ターミナルから、

    open /usr/include/gcc/darwin/3.3/c++/iostream

    と打ってみてください。
     テキストエディットが立ち上がって、ファイルを表示してくれたと思います。これは、Finder上で該当ファイルをダブルクリックしたのと同じことです。iostreamは拡張子のないファイルなので、TextEditで開かれてしまいましたが、.cファイルや.hファイルのようにXcodeで開きたい場合には、以下のようにアプリケーションを指定します。

    open -a Xcode /usr/include/gcc/darwin/3.3/c++/iostream

     「Xcodeを使うなら、直接Xcodeで開けばいいじゃないか」という話も当然あるわけで、この場合には「開く…」ではなく、その下の「すばやく開く…」を使います。まず簡単な方から。既存のC++プロジェクトがある場合はそれでも構いませんが、そうでない場合、新規に「C++ Tool」のプロジェクトを作ります。
     main.cppファイルを開くと先頭にinclude文がありますから、その中のiostreamという文字列を選択します(くれぐれも前後のカッコは選ばないように)。その状態で「すばやく開く…」を選べば、無事に目的のファイルが開かれます。もし、上記のようなinclude文がない場合、ソース上の適当な場所にiostreamと打って、これを選択してから行っても大丈夫。
     もう一つの方法は、何も選んでいない状態で同じく「すばやく開く…」を選びます。するとパスを打ち込むためのダイアログが開きますのでここに目的のパスを入れます。今回のケースでは単にファイル名を入れただけでもOKです。

     あと、「やはりファイルは直接アイコンで扱いたい」という人のための方法。
     Finderには「移動」というメニューがあります。下の方に「フォルダへ移動…」というのがありますね。これを使います。
     メニューを選ぶと、さきほどのXcodeの例と同じようにパスを入れるダイアログが出ますから、ここに「/usr/include/gcc/darwin/3.3/c++」と、目的のファイルの入っているフォルダのパスを入れてやればいいのです。
     ただ実際のところ、ユーザーから隠されているのは単にusrディレクトリだけなので、これを表示させればあとは自分で目的の場所までFinder上で進んで行くことも可能です。
     さて、ご紹介した方法のうち、あなたはいくつご存知でしたか?

    ニュース・解説

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

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

    【開発環境】

    日経BP社のIT Proのサイトに「1000台規模のMacをつなげた日米の研究者二人が語り合ったこと」という内容の興味深い記事が載っています。バージニア工科大学のデータセンタ運用の責任者であるKevin Shinpaugh副所長と、東京大学情報基盤センター情報メディア教育研究部門の安東孝二助手の対談です。
    バージニア工科大学の方は、PowerMac G5を1100台つなげた世界第三位のスーパーコンピュータで、東京大学の方は「教育用計算機システム」としてiMac 1149台を導入して話題を集めました。対談を読むとパソコンの新しい活躍分野の登場に大いに期待が持てます。「個人でスパコンの能力を占有」の時代も近いかもしれませんね(笑)。

    http://itpro.nikkeibp.co.jp/free/ITPro/OPINION/20040604/145374/

    また、「バージニア工科大学のスパコンはいかにして世界最高の価格性能比を記録したか?」と言うKevin Shinpaugh副所長への単独インタビュー記事もありますので、こちらもぜひ参照してください!

    http://itpro.nikkeibp.co.jp/free/ITPro/OPINION/20040527/144941/

    WWDC2004のカンファレンスセッション内容の日本語訳がアップルサイトに登録されました。現地では日本語による解説は入手できないかもしれませんので、これをプリントアウトして持って行くと便利かもしれません。

    http://developer.apple.com/ja/wwdc/descriptions/

    それから、以前ここでも紹介した「Spoken Interface」のプレビュー版を試してみることが可能になりました。正式版はMac OS X 10.4(Tiger)に搭載されるのだと思われます。ちゃんと日本語に対応させるのでしょうか?不安です…。

    http://www.apple.com/accessibility/spokeninterface/download/

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

    前回から6月11日の期間中、Apple社のDocumentationサイトにはドキュメントがひとつも登録されませんでした。しかし、デベロッパ向けの読み物として以下の解説が登録されています。内容は、Javaの開発環境であるEclipseについてです。

    「Eclipse and Mac OS X: A Natural Combination」(読み物)

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

    前回から6月11日の期間中、新規のテクニカルノートはひとつも登録されませんでしたが、テクニカルQ&Aの方は4つ登録されました。

    QA1083「Dynamically registering a bundled component 」
    QA1354「Graphics Exporters – Creating 16-bit-per-channel image files」
    QA1337「Discovering all advertised Rendezvous service types」
    QA1352「New PPD keywords available in Mac OS X version 10.3」

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

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

    前回から6月11日の期間中、Apple社のSample Codeサイトには、新しいサンプルソースコードがふたつ登録されました。めずらしくJava関連のサンプルソースコードも含まれています。

    「OSXAdapter」(Java)
    「DNSServiceMetaQuery 」(Networking)

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

    【デベロップメント SDK】

    前回から6月11日の期間中、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.

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

    2004-06-08

    目次

    • Cocoaでいこう! Macらしく  第53回  Yoshiki(DreamField)
    • 小池邦人の「Carbon API 徒然草」
    • 「Behind the WebObjects」  第21回  田畑 英和
    • ニュース・解説

    Cocoaでいこう! Macらしく  第53回 Yoshiki(DreamField)

    画像を拡大するモードを付けよう(その3)

     今回は前回MyDocumentに実装したメソッドをメニューから呼び出すようにします。具体的には、First Responderにメッセージを投げるようにするわけです。その方法は第50回で説明しましたが、もう一度説明しておきましょう。nibファイルウィンドウでFirst Responderを選んでから、Classesタブでクラスの一覧に切り替えてください(fig.01)。そしてInfoパネルをAttributesに切り替え、Actionタブを選んでください(fig.02)。First Responderで使えるActionの一覧が出ますから、ここで右下のAddボタンを押します(fig.03)。すると、myAction:という名前のActionが追加されますので、これをselectZoomMenu:という名前に書き直します(fig.04)。書き直したら、returnキーを押して確定してください。これでアクションを接続することができるようになりました。説明すると手順は多いのですが、慣れてしまえば無意識に出来るようになるはずです。では、接続しましょう。再びnibファイルウィンドウをInstancesに切り替えてください。コントロールキーを押したままでデザインウィンドウの「View」メニューの「x0.5」メニューをマウスで選択し、そのままnibファイルウィンドウのFirst Responderまで持っていって離します(fig.05)。InfoパネルがTarget/Actionの一覧表示に切り替わりますので、先ほど登録したselectZoomMenu:を選んで、Connectボタンを押してください(fig.06)。これで「x0.5」メニューを選んだらFirst ResponderにselectZoomMenu:メッセージが飛ぶようになりました。残る「x1」と「x2」も同じようにFirst ResponderのselectZoomMenu:に接続してください。selectZoomMenu:メソッドの方でどのメニューが選ばれたのかTagから判断していますので、同じメッセージを飛ばせば良いわけです。

    [fig.01] First Responderを選んでからClassesタブを選択
    http://www.remus.dti.ne.jp/~yoshiki/cocoa/ed1/53/images/fig01.jpg

    [fig.02] InfoパネルでAction一覧を表示
    http://www.remus.dti.ne.jp/~yoshiki/cocoa/ed1/53/images/fig02.jpg

    [fig.03] Addボタンで「myAction:」が追加される
    http://www.remus.dti.ne.jp/~yoshiki/cocoa/ed1/53/images/fig03.jpg

    [fig.04] 「selectZoomMenu:」に書き直す
    http://www.remus.dti.ne.jp/~yoshiki/cocoa/ed1/53/images/fig04.gif

    [fig.05] メニューからFirst Responderまでコントロールキーを押しながらドラッグ
    http://www.remus.dti.ne.jp/~yoshiki/cocoa/ed1/53/images/fig05.jpg

    [fig.06] 「selectZoomMenu:」を選んで「Connect」ボタンを押す
    http://www.remus.dti.ne.jp/~yoshiki/cocoa/ed1/53/images/fig06.gif

     では、ビルドして実行してみましょう。その前にMainMenu.nibを保存することを忘れないでください。保存しなくてもビルドする時に保存を促されますが、この時に保存するとnibファイルがおかしくなることがあるようです。私は一度これで破壊されました。危険は犯さないにこしたことは無いでしょう。
     それでは実行してみてください。適当な画像を開いて、Viewメニューからそれぞれのメニューを選んでみましょう。fig.07の様な表示になったはずです。

    [fig.07] 「x0.5」「x1」「x2」それぞれの表示
    http://www.remus.dti.ne.jp/~yoshiki/cocoa/ed1/53/images/fig07.jpg
    (サンプル画像は、ゆきみだいふくさんのご好意により、使用させていただいています。)

     どうやら拡大縮小はうまくいったようです。でも、これだけでは問題があります。表示する範囲が変わっていませんから、「x0.5」では隙間が出来てしまいますし、「x2」では一部しか表示されません。これにきちんと対処しましょう。
     まずはMyImageViewのサイズを調節することを考えます。MyImageViewは、imageを投影する相手ですから、そのサイズは「x0.5」の時は縦横が半分でなければならず、「x2」の時は2倍でなければならないはずです。これはMyImageView自身に調節してもらうことにしましょう。タイミングとしては、zoomValueをセットした時が適切なはずです。MyImageView.mのsetZoomValue:に、次の様にコードを追加してください。

    - (void)setZoomValue:(float)newZoomValue {
        NSRect theRect;
    
        zoomValue = newZoomValue;
        theRect.size = [ image size];
        theRect.size.width *= zoomValue;
        theRect.size.height *= zoomValue;
        theRect.origin = NSZeroPoint;
        [ self setFrame:theRect];
        [ self setNeedsDisplay:YES];
    }

    やっていることは単純です。imageのサイズを取得し、縦と横それぞれにzoomValueを掛け合わせて、それを自分自身のFrameのサイズにセットしています。これで、MyImageViewのサイズは、常にimageのサイズの縦横をzoomValue倍した大きさになるようになりました。では再びビルドして実行してみましょう。今度は「x2」を選んだ時に、スクロールバーが出るようになったはずです(fig.08)。MyImageViewが適切なサイズになったので、きちんとスクロールさせて見れるようになったのですね。ですが、ウィンドウをこれ以上広げることができません。これは、ウィンドウの最大サイズを最初にセットした時から変えてないからです。この続きの対処は、次回行います。

    [fig.08] スクロールバーにより、全部の範囲を表示できるようになった
    http://www.remus.dti.ne.jp/~yoshiki/cocoa/ed1/53/images/fig08.jpg
    (サンプル画像は、ゆきみだいふくさんのご好意により、使用させていただいています。)

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

    必要なファイルタイプを認識してもらう

    今回は一旦ソースコードから離れ、サンプルアプリケーションでオープン可能なファイルタイプ(種類)をFinderに認識してもらうための手続きについてお話します。アプリケーションパッケージのContentsフォルダに保存される「PkgInfo」と「Info.plist」ファイル、ローカライズリソース用フォルダに保存される「InfoPlist.strings」ファイルについての解説となります。

    CFMベースのCarbonアプリケーションでは、そのアプリのシグネイチャ(OSTypeベース)は、アプリ本体のリソースフォークにオーナリソースとして保存されました。例えば、今回のサンプルのシグネイチャは’MosA’ですので、リソースID=0番の’MosA’リソースを用意することになります。Mach-Oベースのアプリケーションの場合には、アプリケーションパッケージのContentsフォルダ内に、ファイルタイプ’APPL’とシグネイチャ’MosA’の両方を書き込んだPkgInfoファイルを用意します。

    PkgInfoファイルの中身は簡単で、単純に「APPLMosA」と記載されているだけです。これにより、アプリケーションに関係するファイルタイプ、バージョン、開発者、表示アイコンなどすべての情報が、このシグネイチャを手がかりにFinderのデータベースで管理されることになります。例えばMetrowerks CodeWarriorであれば、「Project Setting」ダイアログの「PPC Mac OS X Target」タグにより、PkgInfoファイルの内容を設定することができます。こうしておけば、Makeが完了した時点で、PkgInfoファイルはパッケージの指定場所に自動で保存されることになります。

    次は、開発アプリケーションがどんなタイプのファイルをオープンできるのかをFinderに知らせる方法です。CFMベースのCarbonアプリケーションの場合には、リソースフォークに複数の’BNDL’と’FREF’リソースを用意することで、そのアプリケーションがオープンできる(もしくは管理している)ファイルタイプやアイコンをFinderに指示していました(懐かしい)。Mach-Oベースのアプリケーションの場合には、アプリケーションパッケージのContentsフォルダ内に、XMLで情報を記述したInfo.plistというファイルを保存することで同じ仕組みが実現されています。

    Info.plistの内容をすべて表示すると長くなりますので、今回はその一部だけ抽出して解説したいと思います。以下が、サンプルアプリケーションのInfo.plistの一部です。

    <plist version="1.0">
    <dict>
        <key>CFBundleDevelopmentRegion</key>
        <string>Japanese</string>         // このアプリのディフォルト言語圏
        <key>CFBundleDocumentTypes</key>  // オープン可能ドキュメント情報の一覧
        <array>
            <dict>
        <key>CFBundleTypeIconFile</key>  // ドキュメントのアイコンファイル名
                <string>MosD.icns</string>
                <key>CFBundleTypeName</key>      //Finderの種類カラムの表示内容
                <string>MOSA_Document</string>
                <key>CFBundleTypeOSTypes</key>   // ドキュメントのファイルタイプ
                <array>
                    <string>MosD</string>
                </array>
                <key>CFBundleTypeRole</key>      //  編集可能か?表示するだけか?
                <string>Editor</string>
            </dict>
            <dict>
                <key>CFBundleTypeOSTypes</key>   //フォルダのファイルタイプ
                <array>
                    <string>fold</string>
                </array>
                <key>CFBundleTypeRole</key>
                <string>Viewer</string>
            </dict>
            <dict>
                <key>CFBundleTypeExtensions</key> // JPEGファイルの拡張子
                <array>
                    <string>jpg</string>
                    <string>jpeg</string>
                </array>
                <key>CFBundleTypeIconFile</key>  //JPEGファイルのアイコンファイル名
                <string>jpeg.icns</string>
                <key>CFBundleTypeMIMETypes</key> //  JPEGファイルのMIMEタイプ表記
                <array>
                    <string>image/jpeg</string>
                </array>
                <key>CFBundleTypeName</key>      //Finderの種類カラムの表示内容
                <string>JPEG Image</string>
                <key>CFBundleTypeOSTypes</key> // JPEGファイルのファイルタイプ
                <array>
                    <string>JPEG</string>
                </array>
                <key>CFBundleTypeRole</key>    // JPEGファイルは表示するだけ
                <string>Viewer</string>
                <key>LSIsAppleDefaultForType</key>
                <true/>
            </dict>
        </array>
        <key>CFBundleExecutable</key> // 実行ファイル(アプリ本体)の名称
        <string>MOSA</string
        <key>CFBundleInfoDictionaryVersion</key>  // バンドルインフォのバージョン
        <string>6.0</string>
        <key>CFBundleIconFile</key>   // アプリ自身のアイコンファイル名
        <string>MosA.icns</string>
        <key>CFBundlePackageType</key>  // アプリパッケージのファイルタイプ
        <string>APPL</string>
        <key>CFBundleSignature</key>    // 本アプリケーションのシグネイチャ
        <string>MosA</string>
        <key>CFBundleVersion</key>      // 本アプリパッケージのバージョン
        <string>1.0</string>
    </dict>
    </plist>
    

    この記述であれば、マウスドラッグにより、ファイルタイプが’MosD’と’JPEG’、もしくはフォルダのアイコンがアプリアイコンと重なった時、Finderはそのアイコンをハイライト表示にします。そして、そのままアイコンがドロップされると、対象アプリケーションに対しドキュメントオープンのApple Eventを送るわけです。Dockに対するアイコン操作についても、まったく同じことが言えます。Mac OS 9時代のBNDLリソースとは異なり、Info.plistでは、オープン対象となるファイルの拡張子やインターネットのMIMEタイプも設定できる点に注目してください。

    また、アプリケーション自身やファイルタイプを示すアイコンは、Info.plistに記述されているファイル名(拡張子は.icns)でResourceフォルダに保存すれば、Finderが認識して表示してくれます。複数の言語圏に対してアプリケーションをローカライズする場合には、パッケージのContents/Resourcesフォルダ内に、それぞれの言語圏に対応するフォルダを作成し、その中にローカライズされたNibやリソースファイルを入れておきます。例えば日本語対応するならば、まずは「Japanese.lproj」フォルダを作成し、その中に日本語にローカライズした各種リソース用ファイルを保存するわけです。

    最後に紹介するInfoPlist.stringsは、Finderで「情報を見る」を選択した時に表示される情報(開発者やバージョン)を記述しておくためのファイルです。こうした情報の表示が必要であれば、ローカル言語で記述したInfoPlist.stringsを、各言語圏のフォルダに保存しておきます。以下が、本サンプルのInfoPlist.stringsファイルです。サンプルでは、英語版も日本語版も同じ内容です。ちなみに、各国共通もリソース(アイコン等)については、上位階層のResourcesフォルダにまとめて保存しておけばOKです。

    CFBundleName = "MOSA";
    CFBundleShortVersionString = "MOSA Sample version 1.0";
    CFBundleGetInfoString = "MOSA Sample version 1.0,Copyright 2003 by Ottimo,Inc.";
    

    (注意)ウェブにアップされているサンプルは、InfoPlist.stringsのファイル名が間違っているため正しく情報表示できません(申し訳ない)。直して試してください。

    Info.plistやInfoPlist.stringsは、Xcodeではターゲットに対するプロパティウィンドウで編集することが可能です。CodeWarriorの場合には、「.plc」という拡張子のファイルをプロジェクトに登録し、その中でマクロを使い簡単に記述することができます。このファイルは、プロジェクトテンプレートを作成する時に一緒に保存されるので、その内容を改良して使います。Info.plistの方も最初から記述していては大変です。よって、画像ファイルを沢山扱うようなアプリケーション(プレビューなど)から拝借し、その内容を書き換えて使うのが近道です。ただし、編集をし忘れた箇所があると、借りてきたアプリケーションの情報がそのまま表示されてしまうので注意いたしましょう(笑)。

    次回は、サンプルアプリケーションに実装されているCarbon Event TimerとCarbon Event Handlerの解説をする予定です。

    つづく

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

     前回はWebObjects向けオープンソースプロジェクト「Project WONDER」の概要について解説しましたが、今回はProject WONDERのファイル構成について説明します。

    ダウンロード

     まずはProject WONDERの入手方法ですが、SourceForgeのサイトからダウンロードできます。ここではソースコードおよびビルド済みのものが提供されています。ビルド済みのものはWebObjectsのVer5.1用とVer5.2用が提供されています。SourceForgeのWebサイト上からダウンロード可能な最新版はVer1.0.1ですが、Ver1.0.1がリリースされてからすでに1年以上が経過しており、現在開発中のバージョンはCVSから入手することができます。

    ・Project WONDERダウンロード
    http://sourceforge.net/project/showfiles.php?group_id=45176

    ・WO5.1用ビルド済み
      wonder-1.0.1-wo51.zip
    ・WO5.2用ビルド済み
      wonder-1.0.1-wo52.zip
    ・ソースコード
      wonder-src-1.0.1.tgz

    Ver1.0.1

     それではVer1.0.1でのファイル構成についてみていきましょう。現在開発中のバージョンでは様々な機能追加がおこなわれていますが、こちらはまた正式にリリースされたときにでも取り上げてみたいと思います。
     wonder-src-1.0.1.tgzを解凍するといくつかのディレクトリに分かれていることが分かりますが、今回はProject WONDERで開発がおこなわれているフレームワークなどを含む「Common」ディレクトリに注目してみます。「Common」のディレクトリ構成ですが、次のようになっています。

    ・Applications
      Project WONDERのフレームワークを用いて開発されたアプリケーション
    ・Examples
      サンプルプロジェクト
    ・Frameworks
      フレームワークプロジェクト
    ・ProjectBuilderTemplates
      Project WONDER用のプロジェクトテンプレート

    Common/Applications

     ここには「BugTracker」と「ERMailer」の2つのアプリケーションが収められています。まず「BugTracker」ですが、これはDirect To Webをベースにしたバグトラッキングアプリです。Project WONDERの主要なフレームワークである「ERExtensions」と「ERDirectToWeb」を用いて開発されています。
     次に「ERMailer」ですが、こちらはE-mailの送信をおこなうフレームワーク「ERJavaMail」を使ったE-mail送信アプリです。ただしWebMailのようにWebブラウザ上で入力したデータを送信するのではなく、データベース上に保存されたデータを送信する仕様になっています。E-mailデータのデータベースアクセスはフレームワーク「ERCoreBusinessLogic」で実装されています。

    Common/Examples

     サンプルプロジェクトが収められており、「Stepwise」と「Wrox」ディレクトリから構成されています。「Stepwise」にはDirect To Webのサンプルが2つあり、Stepwise*1 で公開されていた解説記事も収録されています。
     「Wrox」にはWebObjectsの解説本「Professional WebObjects for Java」で紹介されていたケーススタディーに基づいたサンプルが収められています。このサンプルはサンプルアプリ本体の「NetstruxrCaseStudy」と、サンプルで使用しているDirect To Webのルックを実装した「ERMiniUglyLook」から構成されています。

    Common/Examples

     フレームワークのプロジェクトが収められています。一部のフレームワークはすでに前回概要を紹介済みですので、今回は残りのフレームワークを紹介しておきます。

    ・ERCalendar
      iCalなどで使用されているiCalendarドキュメント(.ics)を動的に生成
    ・ERCoreBusinessLogic
      E-mail用データベースのサポートなど
    ・ERNeutralLook
      ERDirectToWebを使用したDirect To Web用ルックのNeutralLookの再実装
    ・ERWorkerChannel
      スレッドを使用してキューイングした処理を実行
    ・JavaWOExtensions
      Appleが提供しているJavaWOExtensionsの修正版
    ・WOOgnl
      WOコンポーネントのバインドへのOGNL*2 の統合

    Common/ProjectBuilderTemplates

     Project WONDER用のプロジェクトテンプレートです。このテンプレートを用いると最初からフレームワーク「ERExtensions」「ERJars」などが追加され、Application/Session/DirectAction.javaがそれぞれ「ERExtensions」で実装されているERApplication/ERSession/ERDirectAction.javaを継承した状態のプロジェクトを生成することができます。
     またこのテンプレートでは「ERExtensions」が提供するLog4jを利用したロギングライブラリのERXLoggerを使用したり、多国語対応をおこなうサンプルにもなっています。Project WONDERを試してみたいとお考えのかたは、まずはこのテンプレートから始めてみてはいかがでしょうか。

    *1 Stepwise
    http://www.stepwise.com/

    *2 OGNL(Object Graph Navigation Language)
    http://www.ognl.org/

    ニュース・解説

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

    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    ┃SQLiteデータベースをCocoaで使うライブラリ
    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    Webbo社は、SQLデータベースのSQLiteをCocoaから使うための「QuickLite」をリリースした。QuickLiteにはCocoaのクラスがいくつか含まれていて、SQLiteの利用をObjective-Cからできるようになっている。また、SQLiteのビルドを含んだサンプルがあるため、それを参考にしてデータベースアプリケーションを作成することが可能だろう。
    SQLiteは軽いデータベースで、MySQLやPostgreSQLに比べて速いことがうたわれているが、サイトではさまざまなテストの詳細な比較を行っている。
    PostgreSQLよりはかなり速いが、MySQLとは僅差というところのようだ。SQL92で定義されている機能で組み込まれていないところでは、LEFT OUTER JOINは利用できるもののRIGHT OUTER JOINやFULL OUTER JOINが使えないこと、ビューへの書き込みができないこと、GRANT関連命令が使えないことがある。
    GRANTは使えないもののファイルへのアクセス権で制限ができるという考え方のようだ。なお、SQLiteはファイル自体を共有する事でデータベースを公開するという考え方のようであり、QuickLiteにも「ネットワーク経由でのアクセス」については不可となっているので、ファイルベースのデータベースと言えるだろう。
    SQLiteにはTclのインタフェースやC言語のライブラリなどがあるが、QuickLiteによってCocoaでオブジェクト指向でデータベースを利用できることになる。ネットワークデータベースではないものの、スピードやオープンソースである事を考慮すると、組み込み用途などでは手軽に使えるかもしれない。

    QuickLite
    http://www.webbotech.com/

    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    ┃SQLiteをネットワーク対応にするサーバをリリース
    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    前の記事で紹介したSQLiteをネットワーク経由で利用できるようにする「SQLiteServer 1.0」をSQLabsがリリースした。Macだけでなく、WindowsやLinux版がある。価格は10クライアント版が$269、無制限アクセス版が$369となっている。ただし、プロトコルは独自のものを利用しており、手軽にアプリケーションを作成するには同社のREALbasic用プラグインである「SQLitePluginPro」($119)を利用するのが手軽な方法だが、REALbasicを使わないでのプロトコルベースでの開発も可能としている。同社では、REALbasicベースでのSQLiteを使うためのさまざまなプラグインなどを開発している。

    SQLabs
    http://sqlabs.net/

    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    ┃16ビット/チャンネルの画像を書き出す方法
    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    Technical Q&Aに掲載された以下の文書で、QuickTimeでのグラフィックエクスポータを使って、チャンネルのビット数が16ビットのPNGやTIFFを書き出す方法が解説されている。文書にサンプルコードが掲載されているが、他のサンプルへのリンクなども掲載されている。

    QA1354: Graphics Exporters – Creating 16-bit-per-channel image files
    http://developer.apple.com/qa/qa2004/qa1354.html

    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    ┃Rendezvousで公開されているサービス一覧を取得する方法
    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    Technical Q&Aに掲載された以下の文書によると、Rendezvousでネットワーク内に公開されたすべてのサービスの一覧を得る事が可能となっている。
    DNSServiceDiscovery APIを利用し、マルチキャストDNSにクエリーを発行する事でリストが得られるとなっている。別途公開されているサンプルコードのページへのリンクもあるので、コードをすぐに見たい場合はそちらを参照すればいいだろう。

    QA1337: Discovering all advertised Rendezvous service types
    http://developer.apple.com/qa/qa2004/qa1337.html

    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    ┃Apple Software Design Guidelinesが新たに独立した文書として公開
    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    「Apple Software Design Guidelines」というドキュメントが公開された。以前に、「Apple Human Interface Guidelines」に含まれていた内容を、新たなドキュメントとして独立させたものである。Apple Software Design Guidelinesは、Mac OS Xで稼働させるアプリケーションなどのソフトウエアを設計するときに考慮すべき内容がまとめられたもので、デザイン上で考慮すべきパフォーマンスや機能性、インストールに関する事、Mac OS X環境での考慮点などがまとめられている。Mac OS Xにおなじみの開発者にとっては当たり前の事かもしれないが、他のプラットフォームの開発者にとっては基礎的なことがまとめられているので必読の文書だろう。もちろん、Macのベテランにとっても、自らの作品のチェックリストとなる。なお、Apple Human Interface Guidelinesからは重複する内容が削除されている。

    Apple Software Design Guidelines
    http://developer.apple.com/documentation/MacOSX/Conceptual/AppleSWDesign/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=モサ伝]第115号

    2004-06-01

    目次

    • Cocoaでいこう! Macらしく  第52回  Yoshiki(DreamField)
    • 藤本裕之のプログラミング夜話 #46
    • 高橋真人の「プログラミング指南」 第45回
    • ニュース・解説

    Cocoaでいこう! Macらしく  第52回 Yoshiki(DreamField)

    画像を拡大するモードを付けよう(その2)

     前回、メニューを実装しましたので、ここで指定した値をimageViewに反映するようにしましょう。まずはMyDocumentでメニューからのメッセージを受け付け、その値をimageViewに設定するようにします。TinyViewのプロジェクトを開いて、MyDocument.mに次のメソッドを追加してください。

    - (IBAction)selectZoomMenu:(id)sender{
        float theZoomValue;
    
        switch( [ sender tag]){
        case 0:
            theZoomValue = 0.5;
            break;
        case 1:
            theZoomValue = 1.0;
            break;
        case 2:
            theZoomValue = 2.0;
            break;
        default:
            return;
        }
        [ imageView setZoomValue:theZoomValue];
    }
    


     やっていることは単純です。senderのTAGを調べて、その値が0なら0.5、1なら1.0、2なら2.0の値を引数とし、setZoomValue:メッセージをimageViewに投げています。senderというのはメッセージを投げた元ですから、この場合はメニューのことですね。前回メニューをInterfaceBuilderで実装する時に、「x0.5」、「x1」、「x2」、それぞれのTAGを0、1、2にしたことを覚えていますでしょうか。ここではTAGの値を元に、本来の数値に変換しています。
     imageViewは、まだsetZoomValue:メッセージを受け付けられませんから、これを実装しましょう。次のインスタンス変数をMyImageView.hに追加してください。

    float zoomValue;

     続けて、次のメソッドの宣言を追加してください。このメッセージを投げられると、MyImageViewはzoomValueに値をセットします。

    - (void)setZoomValue:(float)newZoomValue;

     この結果、MyImageView.hは、次の様になったはずです。

    #import 
    
    @interface MyImageView : NSView {
        NSImage *image;
    
        float zoomValue;
    }
    - (void)setZoomValue:(float)newZoomValue;
    @end

     ヘッダーはできましたので、メソッドを実装しましょう。次のメソッドをMyImageView.mに追加してください。

    - (void)setZoomValue:(float)newZoomValue {
        zoomValue = newZoomValue;
        [ self setNeedsDisplay:YES];
    }
    


     zoomValueに渡された値をセットしています。そして、自分にsetNeedsDisplay:YESを投げて、イベントループで再描画してもらうようにしています。setNeedsDisplayは継承しているNSViewクラスが実装しています。ところで、このメソッドが呼ばれる前のzoomValueの値はいくつでしょうか。インスタンス変数は、インスタンス化の時に0クリアされますから、値は0です。0倍ではまずいですね。そこでイニシャライザでzoomValueの値を1.0にしておきます。

    - (id)initWithFrame:(NSRect)frame {
        self = [super initWithFrame:frame];
        if (self) {
            zoomValue = 1.0;
        }
        return self;
    }

     これでzoomValueの値は良いはずです。肝心の描画部分に手を入れて拡大/縮小表示するようにしましょう。今まで使っていたcomposite系では拡大/縮小はできませんので、draw系を使って全面的に書き直すことにします。ところで、今まではflipを使って座標系を上下反転させていたことを覚えていますでしょうか。実は、今までの経験上、flipした状態でdraw系を使うと、色々な問題が起こることが多いのです(仕様上は起こらないことになっています)。そこで、まずはflipさせるのをやめることにします。次のメソッドを削除してください。

    - (BOOL)isFlipped{
        return YES;
    }

     そして、drawRect:を次の様に書き直してください。

    - (void)drawRect:(NSRect)rect {
        NSRect theSrcRect;
    
        theSrcRect = rect;
        theSrcRect.origin.x /=  zoomValue;
        theSrcRect.origin.y /=  zoomValue;
        theSrcRect.size.width /=  zoomValue;
        theSrcRect.size.height /=  zoomValue;
        [ image drawInRect:rect fromRect:theSrcRect operation:NSCompositeSourceOver 
    fraction:1.0];
    }

     第37回の説明を覚えていますでしょうか。rectで渡って来るのは描画しなければならない範囲ですが、これはMyImageViewの座標です。この範囲に対して、imageの適切な範囲を描画すれば良いわけです。第37回の説明では、MyImageViewのサイズとimageのサイズは等しく、方向も同一であるので、両者の座標は結果として同じになると説明していました。つまり、imageのrectの範囲をMyImageViewのrectの範囲に対して描画すれば良かったわけです。今回は、1倍のサイズで描画する時は従来同様等しいですが、0.5倍で描画する時はMyImageViewのサイズは半分になり、2倍の時は倍になります。では、どうすれば良いかと言うと、拡大する時は描画元のimageの範囲を小さくし、縮小する時は大きくすれば良いわけです(fig.01)。具体的にはrectの各値をzoomValueで割った値になります。上記プログラムでは、theSrcRectはこうやって計算し、imageの描画範囲を割り出しています。そして、drawInRect:fromRect:operation:fraction:で描画しているのですが、これはimageのtheSrcRectの範囲をrectの範囲に描画します。つまり、描画時に拡大
    /縮小を行っているのです。

    [fig.01]青色の範囲のimageを描画すれば等倍、赤色で縮小、水色で拡大になる
    (サンプル画像は、ゆきみだいふくさんのご好意により、使用させていただいています。)
    http://www.remus.dti.ne.jp/~yoshiki/cocoa/ed1/52/images/fig01.jpg

     実を言えば、入門書ではimageそのものを拡大/縮小して描画しているものが多いのですが、今回はあえて違うアプローチを取ってみました。あとは、InterfaceBuilderでメニューからselectZoomMenu:を投げるようにすれば良いわけですが、これは次回に続きます。

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

     20年以上も前の話で恐縮だが、学生のころ「出席さえしていれば必ず単位が貰える」と言われて受講した「農学」のタマイ先生の教えに「原因が判明すれば解決は目前」というのがある。1年間も受講していてその言葉ひとつしか覚えてないのかこのおたんこなす、とか言われそうだがまぁそうなのでしかたがない。もっと言えば4年間に全部で何時間講義を受けたか定かではないが、センセイの言葉ひとつでも覚えている講義の数は覚えてないそれよりずっと少ない。はいはいワタシはウルトラスーパーおたんこなすです、堪忍してください。
     いや、オレのようなヤツを卒業させて良かったのか信州大学、という話ではなくて「原因が判明すれば解決は目前」という話である。タマイ先生は確かこれを「人生で遭遇する諸問題に通用する普遍の真実」であると仰っていたと思うが、オレはプログラミングという仕事中、呪文のようにこの言葉を頭のなかに反響させている。

    読者諸兄にとってプログラミングという仕事で一番楽しい時間はいつだろうか。なに、楽しい時間なんてあるもんか?
     そういうヒトはつまりプログラマに向いてないので、一刻も早く他の仕事を見つけた方がいいと思う。好きこそモノの上手なれという言葉があるが、この仕事はまさにその通りであり、楽しいと思えないヒトには絶対にいいプログラムは書けない。楽しいと思いつつロクでもないものを書いてしまうことはないでもないが、その逆の事態は未来永劫金輪際ないのである。
     話が逸れた。ワタシの場合もっとも楽しいのはコーディング中である。プログラミング仕事というのは大雑把に言って、「課題があり」「解決方法を考案し」「それに沿ってプログラムを作成し」「試験して手直しする」というサイクルで成り立っている。これにタマイ先生の言葉を重ねると、「解決方法を考案し」の部分が「原因が判明すれば」の「未だ判明していない」段階にあたる。オレがその次の「プログラムを作成し」のトコロが楽しいと思うのは早い話「解決は目前」(のような気がする)だから、ですね。
     サイクルの最後の「試験して手直しする」という部分にはほぼ同じサイクルが入れ子のように存在する。「問題が見つかり」「原因を究明し」「対策を講じ」「再度試験する」……この入れ子の中でも「対策を講じ」のフェイズが一番楽しい。「解決は目前」(のような気がする)だからである。
     この「楽しさ」にそんな大きな「解決」は必要ない。例えばコンパイルエラーが取れたとか、いろいろバグはあるもののハングアップはしなくなったとか、もっとミクロなところではどんなケースでハングアップするのか分かったとか、そういう微細なコトを「解決」と感じれば、脳内エンドルフィンが分泌されキモチが良くなるワケなのだ。
     逆に楽しくないと言えば、快感の前段である「解決方法を考案し」とか「原因を究明し」のフェイズということになる。
     楽しくなくなるのは「不安」の増大によるものだ。プログラミングはクイズや試験ぢゃないから正解があるとは限らない。つまり「考えても解決方法はないかも知れない」し「究明できた原因は対策不能かもしれない」という不安が常にある。「探求行為」が長引くと、この「不安」(不安だけでなくその不安が現実になる可能性も)が増大して来る。よって「楽しくなくなって」来るのである。

    こっからは私見……というか偏見かも知れないんだが、この「不安」に対してあんまり我慢強くない方がプログラマとしてはいいような気がする。我慢するよりスパっと諦めてもっとメタな視点から別の解決方法(最終的にはクライアントにその機能を諦めさせるとかね)を探し始めるくらいの軽さというか、ある種のノンシャランさが楽しくプログラマをやってく秘訣ぢゃないかと思うのだ。タマイ先生はどう思われるかわからんが、「遠ざかって行く解決は追わない方がいい」んぢゃないかと(笑)。
    (2004_05_29)

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

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

     こんにちは、高橋真人です。
     さっそく続きです。さて、前回説明したヘッダファイルの取り込み文のところで、「なぜヘッダファイルの名前に拡張子の “.h” がないのだろう?」と疑問に思った方はいませんでしたか?
     実はC++に名前空間の仕組みができたのは、現在のANSI C++になってからのことです。ですから、まだC++に名前空間の概念がなかった当時に書かれたコードにはstdという名前空間の指定は当然存在しません。そのため、古いコードの互換性を維持する理由から、現在のコンパイラでも過去のコードと現在のコードを両立する必要があるということで、このような拡張子のないファイルを新たに作ることで、両者の両立を実現することとなったのです。
     実際にどんな方法で両立を実現しているのかと言えば、新旧両方のヘッダファイルにおいて、共通の部分に関してはコードを共有した形にしてある(片方のファイルで、もう一方のファイルをincludeしてある)ものの、名前空間の部分に関しては、新しいものを取り込んだソースでは有効に、旧い方を取り込んだ場合にはユーザーコードにおいては名前空間を意識する必要がないような仕組みにしてあります。
     コンパイラによってこの「仕掛け」の実現の仕方はいくつかあるようなので、興味のある方は面白いので是非とも実際のヘッダファイルを覗いてみることをお勧めします。
     ちなみにファイルの場所ですが、

    iostream:
    /usr/include/gcc/darwin/3.3/c++/iostream

    iostream.h
    /usr/include/gcc/darwin/3.3/c++/backward/iostream.h

    となります。(gccの場合)
     ところで、stringという名のC++標準ヘッダですが、以前のC++ではstring.hという名前だったかといえばそれは違います。C++はCの上位互換言語という位置付けでもあるため、Cの標準ライブラリは依然としてC++でも利用できます。
     たとえば、C++においては以下の二つの文、

    std::cout << "There are " << 44 << " chairs in the room" << std::endl;
    printf("There are %d chairs in the room n", 44);

    はどちらも同じ出力結果になるのです。
     なのでstring.hというのはCの標準ヘッダとして以前からC++においても有効でした。では、現在のstringに当たるヘッダファイルの以前の名前が何だったかというと、その答えは「そんなヘッダ自体、そもそも存在しなかった」ということです。以前のC++では、文字列を扱うための標準ライブラリクラスが存在しなかったため、そもそもstringという名のクラス自体がなかったというわけなのです。
     ところで、先ほど「Cの標準ライブラリはC++でも有効」と言いましたが、現在のC++において、Cのライブラリ関数などには名前空間の概念は適用されていないのでしょうか?
     もちろん、そんなことはありません。例えば上記のコードではprintf()は裸のままで使っていますが現在のC++で正式な書き方をすると、

    std::printf("There are %d chairs in the room n", 44);

    という書き方になります。
     うーん、そうなると今度はさっきと逆の疑問が出てきます。「名前空間が有効な場合のstring.h(これはCのやつ)は、どんな名前のヘッダになるんだ?」と。
     これがまたぶっ飛んでいます(笑)。ANSI C++においてCのライブラリを使う場合には、なんと頭に "c" を付けることになっているんです。

    #include <cstring>
    #include <cstdio>

    てな感じです。
     慣れないとかなり違和感があるんですが、まあ、すぐに慣れます(笑)。こういう形で取り込むことで、Cの標準ライブラリに関してもstdという名前空間の中にくるまれる形になるわけです。

    ニュース・解説

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

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

    【開発環境】

    随分と前からADCメンバーサイトではダウンロード可能だったのですが、やっと正式にToolsサイトで「Xcode Tools 1.2」が紹介されました。実際に使用してみると、旧バージョンで幾度となく遭遇した「不可解な現象」の頻度は随分と減っているような気がします。このレベルなら安心して開発作業が行えるでしょう。しかし、Xcodeの左側サイドバーのユーザインターフェースですが、非常に分かりづらくストレスが溜まるのは私だけでしょうか(笑)。もう少しすっきりとさせれば、初心者の開発者でも理解しやすいユーザインターフェースが構築できると思うのですが...さて、どうでしょうか?

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

    長い間ADCメンバーサイトでシーディングされていた「Mac OS X 10.3.4 Updater」がついに登場しました。メインマシンのPowerMac G5は元々高速なので、その体感速度にあまり変化を感じませんでしたが、PowerBook G4などで試してみると画面表示など高速化されているような気がします(皆さんはどうですか?)。SafariやFinderもバージョンアップしているようですので、早めのアップデートをお勧めします。Mac OS X 10.3.4が登場したのと同時に、Darwinサイトにもそのバージョンに準拠した「Darwin 7.4」ソースコードが登録されました。興味ある方は覗いてみてください。

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

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

    前回から5月28日の期間中、Apple社のDocumentationサイトにはドキュメントが23も登録されました。例外もいくつかありますが、PDFドキュメントが用意されているものがCarbonやDevice関連、されていないものがCocoa関連と考えればよいでしょう。「Apple Human Interface Guidelines」、「Apple Software Design Guidelines」、「Mac OS X Technology Overview」などは、初めてMacintosh環境の開発に取り組もうとしている人にとっても重要なドキュメントですので、最新版の日本訳が欲しいところです。

    「Apple Human Interface Guidelines」(PDFあり)
    「Apple Software Design Guidelines」(PDFあり)
    「AppleScript for Mac OS X」
    「Application Architecture」
    「Basic Drawing」
    「Certificate, Key, and Trust Services Reference」(PDFあり)
    「Color and Color Management Systems」(PDFあり)
    「Core Foundation Reference」
    「The Drawing Environment」
    「HeaderDoc Unfettered」(PDFあり)
    「I/O Kit Fundamentals」(PDFあり)
    「Keychain Services Reference」(PDFあり)
    「Launch Time Performance」
    「Mac OS X Technology Overview」(PDFあり)
    「Screen Saver Reference for Objective-C」
    「Sheets」
    「Software Distribution」
    「Text System Architecture」(PDFあり)
    「What Is Cocoa?」
    「Working With Bluetooth Devices」(PDFあり)
    「Working With USB Device Interfaces」(PDFあり)
    「Writing an I/O Kit Device Driver」(PDFあり)
    「Adding Search to Your Application (Preliminary)」(PDFあり)

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

    また、デベロッパ向けの読み物として以下の解説が登録されています。有名なSFゲームの「Halo」を開発する時に、OpenGLとApple社のパフォーマンスツールがどのように活躍したのかというお話です。

    「Westlake Puts Halo on the Mac」(読み物)

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

    前回から5月28日の期間中、新規のテクニカルノートはひとつも登録されませんでしたが、テクニカルQ&Aの方は3つ登録されました。

    QA1292「Avoiding the -42 error with DiscRecording」
    QA1351「Directories Appear as Volume Aliases」
    QA1347「Movie export with AAC or AMR audio formats」

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

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

    前回から5月28日の期間中、Apple社のSample Codeサイトには、新しいサンプルソースコードがひとつも登録されませんでした。このままWWDCまでお休みかもしれませんね(笑)。

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

    【デベロップメント SDK】

    前回から5月28日の期間中、Apple社のSDKサイトには新しいSDKがひとつだけ登録されました。Mac OS X 10.3.4に対応した「Kernel Debug Kit」の最新版です。

    「Kernel Debug Kit 10.3.4」

    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.