MOSA Multi-OS Software Artists

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

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

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

2004-08-10

目次

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

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

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

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

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

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

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

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

3 + 4

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

[3 + 4]

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

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

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

[Sensor shiftPressed]

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

“05″ [Sensor shiftPressed not] whileTrue: [

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

[true] whileTrue: []

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

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

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

Sensor redButtonPressed

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

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

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

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

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

Standard Handlerを活用する

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

    witch( cmd.commandID )  // コマンドIDの種類を判断
    {
         case 'new ': // ファイルメニューの「新規」

             newCatalogWindow( &wptr );  // 新規ファイルルーチン
             ret=noErr;                  // ここでストップ
             break;

         case 'open': // ファイルメニューの「開く...」

              loadCatalogFile( &wptr );  // ファイルロードルーチン
              ret=noErr;                 // ここでストップ
              break;

         case 'abou': // アプリメニューの「MOSAについて...」

              openAboutWindow();         // アバウト表示
              ret=noErr;                 // ここでストップ
              break;

         case 'quit': // アプリメニューの「MOSAを終了」

              if( quitApplication() )   // アプリケーションの終了
                  ret=noErr;            // ここでストップ(終了はしない)
              break;
    }
    break;


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

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

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

OSStatus ret=eventNotHandledErr;

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

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

        case 'abou':

         //   openAboutWindow();
              ret=noErr;
              break;


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

        case 'abou':

             openAboutWindow();
         //  ret=noErr;
             break;


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

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

short quitApplication(void)
{
    WindowRef        wptr[MAX_BUF];
    unsigned long    i,ct;
    short            ret;

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


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

         case 'quit':

              if( quitApplication()==0 )
                 QuitApplicationEventLoop();
              ret=noErr;
              break;


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

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

つづく

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

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

OpenJMSセットアップ

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

ERChangeNotificationJMS.frameworkセットアップ

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

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

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

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

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

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

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

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

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

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

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

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

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

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

ニュース・解説

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

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

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

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

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

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

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

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

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

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

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