Apple Developer Connection
Advanced Search
Member Login Log In | Not a Member? Contact ADC

< Previous PageNext Page >

通知

オブジェクト間で情報を受け渡す標準的な方法はメッセージの受け渡しです。すなわち、あるオブジェクトが別のオブジェクトのメソッドを呼び出すというものです。しかし、メッセージの受け渡しでは、メッセージを送信するオブジェクトは受信側が何であり、どのメッセージに応答するかを知っている必要があります。このような要件は、委任メッセージだけでなく、他のタイプのメッセージにも当てはまります。2つのオブジェクトをこのように緊密に結び付けることは、極端にいうと、2つの独立したサブシステムを1つにまとめることになるので、望ましくない場合もあります。また、アプリケーション内のさまざまなオブジェクト間にハードコードされた接続が必要になるため、実用的とはいえません。

標準的なメッセージの受け渡しだけでは間に合わない場合のために、Cocoaではブロードキャストによる通知を用意しています。この通知メカニズムを使用することで、オブジェクトは、それが何を実行しているかを、他のオブジェクトに通知し続けることができます。この点では、通知は委任に似ていますが、その違いは重要です。委任と通知の重要な違いは、委任は(委任元のオブジェクトとそのデリゲーションの間の)通信経路が1対1であることです。一方、通知は潜在的に1対多の通信形態、すなわちブロードキャストです。オブジェクトは、デリゲートを1つしか持てませんが、通知の場合は受信者が分かっているので、多数の「オブザーバ」を持てます。また、オブジェクトは、それらのオブザーバが何であるかを知っている必要もありません。オブジェクトは通知を通じてイベントを間接的に監視し、イベントに応じて自身の外観、動作、状態を調整できます。プログラム内で連携と結束を実現するには、通知は強力なメカニズムです。

通知メカニズムの仕組みは、概念的には単純です。プロセスには通知センターというオブジェクトがあります。これは、通知のための情報センターと放送センターの役割を果たします。アプリケーションのどこかほかの場所で発生するイベントについて知る必要のあるオブジェクトは、イベントが発生したときに通知してくれるよう通知センターに登録します。たとえば、コントローラオブジェクトは、ポップアップが選択されたときに、その変化を認識してユーザインターフェイスに反映できなければなりません。イベントが発生すると、そのイベントを処理するオブジェクトが通知センターに通知を送り、センターがそのオブザーバすべてに通知を配信します。Figure 5-6に、このメカニズムを示します。

注: 通知センターは、オブザーバに対して通知を同期的に配信します。通知の送信すべてが完了するまで、送信側のオブジェクトには制御は戻りません。通知を非同期に送信するには、通知キューを使用する必要があります(“「通知キュー」”を参照)。通知キューは、指定された通知を遅らせ、指定された何らかの基準に従って類似した通知を1つにまとめてから、通知センターに通知を送信します。


Figure 5-6  通知の送信とブロードキャスト

Figure 5-6 通知の送信とブロードキャスト

任意のオブジェクトが通知を送信でき、自身を通知のオブザーバとして通知センターに登録することができます。通知を送信するオブジェクト、通知に含まれるオブジェクト、および通知のオブザーバはすべて別々のオブジェクトでも、同じオブジェクトでも構いません(送信側のオブジェクトと監視するオブジェクトを同じにすると、アイドル時間の処理などに役に立ちます)。通知を送信するオブジェクトは、オブザーバについて知る必要はありません。これに対して、オブザーバは少なくとも通知名と、通知オブジェクトによってカプセル化されたディクショナリのキーを知る必要があります(通知オブジェクトの構成については、“「通知オブジェクト」”を参照してください)。

参考資料: 通知メカニズムの詳細な解説については『Notification Programming Topics』を参照してください。

In this section:

通知はいつどのように使用するべきか
通知オブジェクト
通知センター
通知キュー


通知はいつどのように使用するべきか

委任の場合と同様、通知メカニズムはアプリケーション内のオブジェクトどうしの通信を可能にする優れたツールです。通知によって、アプリケーション内のオブジェクトは、そのアプリケーションの他の場所で生じた変更について知ることができます。一般に、オブジェクトは、特定のイベントが発生したときや、発生しようとしているときに調整が必要になるため、通知のオブザーバとなるように登録されます。たとえば、カスタムビューのウインドウサイズが変更されたときにその外観を変更する必要がある場合、カスタムビューはそのウインドウオブジェクトによって送信されるNSWindowDidResizeNotificationを監視することができます。通知にはイベントに関するデータのディクショナリを含めることができるので、通知を使ってオブジェクト間で情報を受け渡すこともできます。

ただし、通知と委任にはいくつかの相違があり、その相違が、これらのメカニズムを何の目的で使用すべきかを決定付けています。前述のとおり、通知モデルと委任モデルの主要な違いは、通知がブロードキャストメカニズムであるのに対して、委任が1対1の関係であるということです。各モデルにはそれぞれ利点があります。通知の場合は以下のとおりです。

ただし委任の1対1モデルには、次の利点もあります。デリゲートには、委任元オブジェクトに値を戻すことで、イベントに影響を与える機会が与えられます。これに対して、通知オブザーバの役割はそれよりも受動的であり、イベントに応じて、通知オブザーバ自身とその環境に対してのみ影響を与えることができます。通知メソッドは、次のシグネチャを持つ必要があります。

- (void)notificationHandlerName:(NSNotification *);

この要件により、監視するオブジェクトは元のイベントに直接影響を与えることができません。しかし、デリゲートは委任元のオブジェクトがイベントを処理する方法にしばしば影響を与えます。さらに、Application Kitオブジェクトのデリゲートとなるオブジェクトは、自動的に通知のオブザーバとして登録されます。必要なのは、フレームワーククラスでその通知に対して定義した通知メソッドを実装することだけです。

通知メカニズムは、オブジェクト状態の変化を監視するための、Cocoaの唯一の選択肢ではなく、実際に多くの状況において、望ましい選択肢とはいえません。Cocoaのバインディングテクノロジー、特にそれを可能にしているキー値監視(KVO)プロトコルとキー値バインディング(KVB)プロトコルを使用することによっても、アプリケーション内のオブジェクトは他のオブジェクトのプロパティの変化を監視することができます。バインディングメカニズムは、通知よりも効率よくこの役目を果たします。バインディングでは、監視対象のオブジェクトと監視元のオブジェクトの間の通信がダイレクトに行われ、通知センターのような仲介オブジェクトを必要としません。さらに、バインディングメカニズムの場合、監視対象以外の変更に対しては、通常の通知のようなパフォーマンスへの影響がありません。

ただし、バインディングよりも通知のほうが好ましい状況もあります。オブジェクトプロパティの変更以外のイベントを監視したい場合があります。あるいは、KVOおよびKVBに準拠した実装が現実的でない場合があります。送信され、監視の対象となる通知の数が少ない場合は特にそうです。

通知の使用が正当化されるような状況であっても、パフォーマンスへの影響を認識しておく必要があります。通知を送信すると、最終的にはローカルの通知センターによって監視元のオブジェクトに同期的に配信されます。これは、送信が同期か非同期かに関係なく行われます。オブザーバが多数存在する場合や、通知の処理中に各オブザーバが大量の作業を行うような場合、プログラムは極端に遅くなることがあります。このため、通知を使い過ぎたり、効率の悪い使い方をしたりしないように注意する必要があります。通知の使用についての次のガイドラインが、この目的に役立ちます。

参考資料: 通知の効率良い使い方の詳細については、『Cocoa Performance Guidelines』の「Notifications」を参照してください。

通知オブジェクト

通知はオブジェクトであり、NSNotificationのインスタンスです。通知オブジェクトは、ウインドウがフォーカスを得たり、ネットワーク接続が終了したりするなどのイベントに関する情報をカプセル化します。イベントが発生すると、イベントを処理するオブジェクトが通知センターに通知を送信し、その通知が即座にセンターから登録されているすべてのオブジェクトにブロードキャストされます。

NSNotificationオブジェクトには、名前、オブジェクト、およびオプションのディクショナリが含まれています。名前は通知を識別するタグです。オブジェクトは、通知の送信元が、その通知のオブザーバに送信したいオブジェクトです(通常は、通知を送信したオブジェクトです)。これは委任メッセージの送信元オブジェクトに似ており、レシーバは詳細をこのオブジェクトに照会することができます。ディクショナリは、イベントに関する情報を格納しています。

通知センター

通知センターは通知の送受信を管理します。特定の基準に合った通知をすべてのオブザーバに知らせます。通知情報は、NSNotificationオブジェクトにカプセル化されています。クライアントオブジェクトは、他のオブジェクトによって送信される特定の通知のオブザーバとして、自身を通知センターに登録します。イベントが発生すると、オブジェクトは適切な通知を通知センターに送信します。通知センターは、登録されている各オブザーバにメッセージを配信し、唯一の引数として通知を受け渡します。送信するオブジェクトと監視するオブジェクトが同じ場合もあります。

Cocoaには、2種類の通知センターがあります。

他の多くのFoundationクラスとは異なり、NSNotificationCenterは、対応するCore Foundation(CFNotificationCenterRef)に負担なしでブリッジされるものではありません。

NSNotificationCenter

各タスクには、NSNotificationCenterクラスメソッドのdefaultCenterを使用してアクセスするデフォルトの通知センターがあります。この通知センターは、1つのタスク内の通知を処理します。同じマシン上のタスク間の通信ついては、分散通知センターを使用してください(“「NSDistributedNotificationCenter」”を参照)。

通知センターはオブザーバに対して同期的に通知を配信します。つまり、通知を送信すると、すべてのオブザーバが通知を受信して処理を完了するまで、送信側に制御が戻りません。通知を非同期に送信するには、通知キューを使用します(“「通知キュー」”を参照)。

マルチスレッド型のアプリケーションでは、通知は必ず、それを送信したスレッド内で配信されます。オブザーバが自身を登録したスレッドと同じでなくても構いません。

NSDistributedNotificationCenter

各タスクには、NSDistributedNotificationCenterクラスメソッドのdefaultCenterでアクセスするデフォルトの通知センターがあります。この分散通知センターは、単一マシン上のタスク間で送信できる通知を処理します。異なるマシン上のタスク間の通信については、分散オブジェクトを使います(『Distributed Objects』を参照)。

分散通知の送信は負担の大きい処理になります。通知はシステム全体のサーバに送信されてから、分散通知の対象としてオブジェクトを登録しているすべてのタスクに配信されます。通知を送信してから、それが別のタスクに届くまでの待ち時間に制約はありません。実際、大量の通知が送信されて、サーバのキューがいっぱいになった場合は、通知が欠落することもあります。

分散通知は、タスクの実行ループを通じて配信されます。分散通知を受信するには、タスクは、NSDefaultRunLoopModeなどの何らかの「一般的な」モードで実行ループを実行していなければなりません。受信側のタスクがマルチスレッド化されている場合は、通知がメインのスレッドに届くことを想定しないでください。通知はたいていメインのスレッドの実行ループに配信されますが、他のスレッドが通知を受信する可能性もあります。

通常の通知センターの場合は任意のオブジェクトが通知オブジェクト(通知でカプセル化したオブジェクト)になれますが、分散通知センターの場合は、通知オブジェクトはNSStringオブジェクトに限られます。送信側のオブジェクトとオブザーバは異なるタスク内にある可能性もあるため、通知には任意のオブジェクトへのポインタを含むことはできません。このため分散通知センターの場合は、通知は通知オブジェクトとして文字列を使用する必要があります。通知の照合は、オブジェクトポインタではなく、この文字列を使って行われます。

通知キュー

NSNotificationQueueオブジェクト(通知キュー)は、通知センター(NSNotificationCenterのインスタンス)のバッファの役割を果たします。通知キューは、一般にFIFO(先入れ先出し)の順番で通知(NSNotificationのインスタンス)を保持します。通知がキューの先頭に来ると、キューがそれを通知センターに送信し、次にオブザーバとして登録されているすべてのオブジェクトに通知が配信されます。

どのスレッドにも、タスクのデフォルト通知センターと結び付いているデフォルトの通知キューがあります。Figure 5-7に、これを示します。通知キューを独自に作成し、センターやスレッドごとに複数のキューを持つことができます。


Figure 5-7  通知キューと通知センター

Figure 5-7 通知キューと通知センター

通知の結合

NSNotificationQueueクラスは、Foundation Kitの通知メカニズムに2つの重要な機能を提供します。すなわち、通知の結合と非同期の送信です。結合は、キューに入ったばかりの通知に類似した通知を、キューから削除する処理です。新しい項目が、すでにキューに入っている通知に類似している場合、新しいものはキューには入れられず、類似した通知がすべて(キューの先頭にあるものは除いて)削除されます。ただし、このように特殊な結合の動作には依存しないでください。

類似性の基準を指定するには、enqueueNotification:postingStyle:coalesceMask:forModes:メソッドの第3引数に以下の定数を指定します(複数も可)。

NSNotificationCoalescingOnNameNSNotificationCoalescingOnSender定数を使ってビットごとのOR演算を実行し、通知名と通知オブジェクトを使用した結合を指定できます。

通知の非同期送信

NSNotificationCenterのメソッドpostNotification:とそのバリエーションを使って、通知センターにすぐに通知を送信できます。しかし、メソッドの呼び出しは同期的です。送信側のオブジェクトがその実行のスレッドを再開するには、通知センターがすべてのオブザーバに通知を配信して戻ってくるまで、待つ必要があります。しかし、NSNotificationQueueメソッドのenqueueNotification:postingStyle:enqueueNotification:postingStyle:coalesceMask:forModes:メソッドを使えば、通知をキューに入れて非同期で送信できます。これらのメソッドは、通知をキューに入れると、すぐに呼び出し元オブジェクトに戻ってきます。

通知キューが空にされ、エンキューメソッドで指定された送信スタイルと実行ループモードに基づいて通知が送信されます。モード引数は、キューを空にするための実行ループモードを指定します。たとえば、NSModalPanelRunLoopModeを指定すると、実行ループモードがこのモードにある場合にのみ、通知が送信されます。実行ループが現在このモードにない場合、通知は次にこのモードに入るまで待機します。

通知キューへの送信は、3つのスタイル、すなわちNSPostASAP(できるだけ早く送信)、NSPostWhenIdle(待機時に送信)、NSPostNow(すぐに送信)のいずれかで起こる可能性があります。これらのスタイルについては、以下のセクションで説明します。

できるだけ早く送信

現在の実行ループモードが要求されたモードに一致している場合に、NSPostASAPスタイルでキューに入れられた通知は、実行ループの現在の繰り返しが完了したときに通知センターに送信されます(要求されたモードと現在のモードが異なる場合は、通知は要求されたモードに入ったときに送信されます)。実行ループは、1回の繰り返しの間に何度も呼び出せるため、現在の呼び出しが終了して、実行ループに制御が戻ったあと、すぐには配信されないこともあります。まず、タイマーやソースの解放、他の非同期通知の配信など、他の呼び出しが先に行われます。

ディスプレイサーバなどの高価なリソースには、一般にNSPostASAPの送信スタイルを使用します。多数のクライアントが実行ループからの呼び出し時にウインドウバッファ上に描画している場合、描画動作のたびにバッファをディスプレイサーバにフラッシュするのは高くつきます。このような状況では、それぞれのdraw...メソッドによって、指定された名前とオブジェクトに基づく結合と、NSPostASAP送信スタイルが設定された「FlushTheServer」などの通知がキューに入れられます。その結果、これらの通知のうち1つだけが実行ループの最後に配信され、ウインドウバッファが一度だけフラッシュされます。

待機時に送信

NSPostWhenIdleスタイルを指定されてキューに入れられた通知は、実行ループが待機状態のときにのみ送信されます。この状態では、タイマーにしろ他の非同期イベントにしろ、実行ループの入力チャネルには何もありません。NSPostWhenIdleスタイルを使ったキューの典型的な例は、ユーザがテキストを入力し、プログラムがそのテキストの量をバイト数としてどこかに表示する場合などです。ユーザが文字を入力するたびに(特にユーザの入力が速い場合は)、テキストフィールドのサイズを更新するのは非常に高くつきます(しかも、あまり役に立ちません)。このような場合、プログラムは文字が入力されるたびに、結合を有効にし(結合の結果)送信スタイルをNSPostWhenIdleに設定した「ChangeTheDisplayedSize」などの通知をキューに入れます。ユーザが入力を停止し、実行ループが待機状態に入ると、キューに内の1つの「ChangeTheDisplayedSize」通知が送信され、ディスプレイが更新されます。終了間近の実行ループ(入力チャネルがすべて終了したときに発生する)は待機状態ではないため、通知は送信されません。

すぐに送信

NSPostNowを指定してキューに入れられた通知は、結合のあとすぐに通知センターに送信されます。非同期の呼び出し動作を必要としない場合は、NSPostNowを使って通知をキューに入れます(または、NSNotificationCenterメソッドのpostNotification:を使って送信します)。多くのプログラミング状況では、同期動作が可能なだけでなく、望ましいのです。配信後に通知センターから戻るようにすることで、オブザーバオブジェクトが通知を受信して処理したことを確認できます。もちろん、結合を利用して削除したい類似の通知がキューにある場合は、postNotification:ではなく、enqueueNotification... とNSPostNowを使用します



< Previous PageNext Page >


Last updated: 2006-05-23




Did this document help you?
Yes: Tell us what works for you.

It’s good, but: Report typos, inaccuracies, and so forth.

It wasn’t helpful: Tell us what would have helped.
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