|
|
Log In | Not a Member? |
Contact ADC |
| < Previous PageNext Page > |
すべてのCocoaアプリケーションは単一のNSApplicationオブジェクトによって管理されます。通常、このオブジェクトはNSAppという名前のグローバル変数です。このグローバルアプリケーションオブジェクトはNSApplication(またはそのカスタムサブクラス)のシングルトンインスタンスですが、これには、アプリケーションをターゲットとするユーザイベントとシステムイベントを取得し、それらを該当するオブジェクトにディスパッチする、という重要な役割があります。また、アプリケーションのウインドウを管理する役割も担っています。たとえば、ウインドウの現在の状態をキーまたはメインウインドウとして追跡します(“「ウインドウのステータス」”を参照)。
メインイベントループ
イベントのディスパッチについて
ウインドウの管理
アップルイベントの処理
NSAppによって実行される処理のほとんどはアプリケーションのメインイベントループの中で発生します。メインイベントループはイベントおよび描画サイクルの基礎となるものです。このループの仕組みを理解するために、Cocoaアプリケーションのmainエントリポイントで何が起きるかを考察してみましょう。標準的なXcode Cocoaプロジェクトでは、mainにはNSApplicationMainという関数呼び出しが1つあります。この関数は、3つの重要な処理を以下の順序で実行します。
アプリケーションを実行する([NSApp run ])。
これらの処理についてもう少し詳しく調べてみましょう。まず、いくつかの基本的なことがらについて説明します。実行中のアプリケーションは本質的にはプロセスです。各プロセスはメインスレッドを持ち、1つ以上の二次スレッドを持つことがあります。スレッドはそれぞれ、スレッド用に作成された実行ループを持ちます。実行ループは、プロセスへの入力ソースを監視し、入力ソースが処理の準備を完了した時点でプロセスに制御をディスパッチするためのメカニズムです。
sharedApplicationメソッドには、シングルトンインスタンスを保証するということ以外に、ウインドウサーバからのイベントを受信して処理するためのプログラムインフラストラクチャを準備するという重要な役割もあります。グローバルアプリケーションオブジェクトの初期化の中で、NSApplicationは、イベントを受信するためのイベントソースを作成することによって(Machポートとして実装されます)、ウインドウサーバへの接続を確立します。また、アプリケーションのイベントキューも準備します。イベントキューは、イベントソースから送信されたイベントを受信してキューに配置するためのFIFOメカニズムです。最後に、NSApplicationは、イベントソースを入力ソースとして使用し、メイン実行ループ(メインスレッドの実行ループ)を初期化します(Figure 6-2を参照)。
ウインドウサーバは、I/O Kitデバイスドライバからイベントを受信し、それらを該当するプロセスにディスパッチします。プロセスは、実行ループにあるイベントソースからイベントを受信してキューに置きます。
アプリケーションがメインnibファイルをロードすると、ファイル内のオブジェクトと、それらのオブジェクト間の接続が展開されます。メインnibファイルにはアプリケーションメニューが必ず含まれます。また、1つ以上のウインドウオブジェクトが(それらを構成するビューと一緒に)含まれる場合があります。それ以外のnibファイルについても同様に、起動時に展開される場合があります。たとえば、ドキュメントベースのアプリケーションでは、ユーザがFinderの中でファイルをダブルクリックしたときに書類のnibファイルを展開できます。この最初のグラフィカルユーザインターフェイスは、ユーザが(メニュー項目を選ぶなどの)要求を開始するために必要です。そしてその結果、アプリケーションで処理されるイベントが生成されます。
メインイベントループで処理の中心的な役割を果たすのが、NSApplicationのrunメソッドです。このメソッドは、最初にアプリケーション用のアップルイベントハンドラを登録します(“「アップルイベントの処理」”を参照)。次に、閉じたwhileループの中で、runはアプリケーションが終了するまで以下を実行します。
実行ループで保留中となっているウインドウ表示オブザーバに対して、サービスを提供する(Figure 6-3を参照)。この結果、「ダーティ」としてマークされているウインドウ内のリージョンが再描画される。
イベントキューにある次のイベントを取得する(nextEventMatchingMask:untilDate:inMode:dequeue:)。
イベントを次に処理する必要のあるオブジェクトに、イベントをディスパッチする。ほとんどの場合、これはNSWindowオブジェクト(sendEvent:)である。詳細については、“「イベントのディスパッチについて」”を参照のこと。
最終的には、多数のオブジェクトがイベントの処理に関与する可能性があり、呼び出しスタックのサイズがかなり大きくなる場合がある。イベントが処理された後、runに制御が戻る。
nextEventMatchingMask:untilDate:inMode:dequeue:メソッドは、メインイベントループにおいて漏斗のような役割を果たします。このメソッドは、イベントキューにイベントがあれば、キューの一番上にあるイベントをフェッチし、その構造をNSEventオブジェクトに変換します。キューにイベントがなければ、メソッドがブロック状態になります。メソッドがブロック状態にある間は、ウインドウサーバからの新しいイベントが処理されてキューに置かれます。新しいイベントの存在によって、nextEventMatchingMask:untilDate:inMode:dequeue:が「呼び起こされ」、キュー内で最初に一致するイベントが返されます。
ウインドウの自動表示機能が有効になっていて、要表示としてマークされているビューがウインドウにある場合は、そのウインドウによってオブザーバ(入力ソース)も実行ループにインストールされます。NSAppによってキュー内の次のイベントが処理される直前に、このオブザーバが作動し、その結果として対応するビューが再描画されます。ウインドウ内容の自動表示の詳細については、“「ウインドウと描画」”を参照してください。
NSAppは、自身のsendEvent:実装の中で、渡されたイベントの種類を調べ、それに応じてイベントをディスパッチします。通常、ディスパッチのターゲットはアプリケーションのウインドウの1つであり、アプリケーションはそのNSWindowオブジェクトのsendEvent:メソッドを呼び出すことによって、イベントを転送します。NSAppでは、主要な入力イベントであるキーイベントとマウスイベントの2種類のイベントについて、該当するウインドウを見つけるために、それぞれ異なるアプローチが使用されます。
ユーザがキーボードのキーを押すと、キーイベントが生成されます。NSAppはこれらのイベントをキーウインドウ(現在キー押下を受け付けているアプリケーションのウインドウ)に転送します(代替キーストロークなど、場合によっては、ディスパッチをせずにアプリケーションでNSKeyDownイベントを特別に処理することもあります)。
ユーザがマウスを使用してウインドウ上のオブジェクト(たとえば、描画プログラムのグラフィカル図形など)をクリックすると、マウスイベントが生成されます。NSAppはこれらのマウスイベントを、そのマウスイベントが発生したウインドウにディスパッチします。
クリックその他の操作の対象となっているオブジェクトがコントロールオブジェクト(ボタンやスライダなど)の場合、そのオブジェクトから、アクションメッセージと呼ばれる追加のメッセージがアプリケーションに送信されます。アクションメッセージによって、NSApplicationのsendAction:to:from:メソッドが呼び出されます。メッセージのターゲットが指定されていない場合、このメソッドはアプリケーションのキーウインドウ(および必要ならばメインウインドウ)のレスポンダチェーンで、適切なターゲットを検索します。そして、メッセージをアクションメッセージのターゲットに送信します。
ほかの種類のイベントについては、NSAppはsendEvent:で処理します。イベントによってはアプリケーションに固有のもの(アクティブ化や非アクティブ化など)があり、それらはNSApp自身が処理します。あるいは、1つ以上のウインドウに関連するイベントもあります。たとえば、ウインドウが露出された場合や、画面の解像度が変更された場合などです。このようなイベントについては、NSAppは作用を受けるウインドウで該当するメソッドを呼び出します。
参考資料: レスポンダチェーンについては“「レスポンダとレスポンダチェーン」”で説明しています。キーウインドウの詳細については、“「ウインドウのステータス」”を参照してください。NSControlオブジェクト、およびNSControlオブジェクトとNSCellオブジェクトの連携動作の詳細については、“「コントロールとメニュー」”を参照してください。
グローバルアプリケーションオブジェクトの役割の1つは、アプリケーションのウインドウを管理することです。NSAppは以下のウインドウ管理処理を実行します。
ウインドウの表示と非表示を切り替える。
アプリケーションの終了時にウインドウの割り当てを解除する。
アプリケーションの切り替え時にウインドウのアクティブ化および非アクティブ化を管理する。
そして、“「イベントのディスパッチについて」”で説明したように、NSAppはウインドウ固有のイベントとアクションメッセージを、作用を受けるウインドウにディスパッチします。また、アプリケーションの「ウインドウ」メニューを管理し、モーダルウインドウとパネルを管理します(“「モーダルウインドウ」”を参照)。
ウインドウを見つけやすくするため、アプリケーションオブジェクトはウインドウリストと呼ばれる、ウインドウへの参照を維持します(Figure 6-4を参照)。ウインドウ管理処理によっては(割り当て解除など)、このリストを反復処理するものがあります(ウインドウリストはwindowsをNSAppに送信することによっていつでも取得できます)。また、アプリケーションオブジェクトはウインドウを検索する際、windowWithWindowNumber:呼び出しの中で現在のNSEventオブジェクトから取得したウインドウ番号も使用します。
注: NSAppは、画面上のウインドウの重なり(Z軸順)に関しては何もしません。Z軸順はウインドウサーバによって管理されます。ウインドウのZ軸順の詳細については、“「ウインドウのZ軸順とレベル」”を参照してください。
アプリケーションで処理する必要のあるイベントは、必ずしもそのすべてがイベントキューから取得されるとは限りません。Mac OS Xシステム上の他のプロセス(FinderやLaunch Servicesなど)は、アップルイベントを使用してほかのプロセスとやり取りします。これらのプロセスは、たとえばユーザがFinderウインドウで書類をダブルクリックしたときや、アップルメニューから「システム終了」を選んだためにアプリケーションを終了させる必要があるときなどに、アプリケーションに通知を行うために、しばしばアップルイベントを送信します。
Cocoaアプリケーションが起動時に実行する処理の1つとして、いくつかのアップルイベントハンドラの登録があります。アップルイベントがアプリケーションに送信されると、対応するハンドラが呼び出されます。Cocoaアプリケーションは以下のアップルイベント用のハンドラを登録します。
アップルイベントID | 説明 |
|---|---|
| アプリケーションを起動します。 |
| アプリケーションを再び開きます。たとえば、アプリケーションの実行中にユーザがDockでアプリケーションアイコンをクリックしたときなどに、このイベントが送信されます。 |
| 開く書類のリストをアプリケーションに提供します。通常は、ユーザがFinderで1つ以上の書類を選択し、書類をダブルクリックしたときに、このイベントが送信されます。 |
| プリントする書類のリストをアプリケーションに提供します。通常は、ユーザがFinderで1つまたは複数の書類を選択し、「ファイル」メニューから「プリント」を選んだときに、このイベントが送信されます。 |
| ドラッグされている内容(テキストや画像など)をアプリケーションに提供します。多くの場合、ユーザがDockでアプリケーションのアイコンの上にファイルをドラッグしたときに、このイベントが送信されます。 |
| アプリケーションに対して終了するよう要求します。 |
| < Previous PageNext Page > |
Last updated: 2006-05-23
|
Get information on Apple products.
Visit the Apple Store online or at retail locations. 1-800-MY-APPLE Copyright © 2007 Apple Inc. All rights reserved. | Terms of use | Privacy Notice |