通知キュー
NSNotificationQueue オブジェクト、または単に 通知キュー は、通知センター (NSNotificationCenter のインスタンス) のバッファとして機能します。NSNotificationQueue クラスは、Foundation Kit の通知メカニズムに 2 つの重要な機能である、通知の統合と非同期通知を提供します。
通知キューの基本
NSNotificationCenter の postNotification: メソッドとそのバリエーションを使用すると、通知センターに通知を送信できます。ただし、メソッドの呼び出しは同期的です。送信するオブジェクトがその実行スレッドを再開できるようになる前には、通知センターがすべての監視者に通知を急送して戻るまで待たなければなりません。一方、通知待ちキューは、通常、先入れ先出し (FIFO) の順番で通知 (NSNotification のインスタンス) を維持します。通知がキューの先頭に上がると、キューは通知センターにそれを送信し、通知センターは監視者として登録されたすべてのオブジェクトに通知を送ります。
すべてのスレッドには、プロセスのデフォルトの通知センターに関連したデフォルトの通知キューがあります。独自の通知キューを作成して、センターとスレッドごとに複数のキューを持つ事ができます。
通知を非同期的に通知
NSNotificationQueue の enqueueNotification:postingStyle: および enqueueNotification:postingStyle:coalesceMask:forModes: メソッドを使用すると、現在のスレッドをキューに入れることで、非同期的に通知を送信できます。これらのメソッドは、通知をキューに入れた後、直ちに呼び出し元オブジェクトに戻ります。
通知キューが空になり、待ち行列に入れる (enqueing) メソッドで指定された送信スタイル (posting style) と実行ループモードに基づいてその通知は、送信されます。mode 引数は、キューが空になる実行ループモードを指定します。たとえば、NSModalPanelRunLoopMode を指定した場合、通知は実行ループがこのモードにある場合にのみ送信されます。実行ループが現在このモードにない場合、通知はそのモードが次回入力されるまで待機します。詳細については、実行ループモード を参照してください。
通知キューへの送信は、NSPostASAP、NSPostWhenIdle、および NSPostNow という 3 つの異なるスタイルのいずれか 1 つで実行できます。これらのスタイルについては、以下のセクションで説明します。
出来るだけ早く送信 (ASAP)
現在の実行ループモードが、要求されたモードと一致すると仮定して、実行ループの現在の繰り返しが完了すると、NSPostASAP スタイルで待ち行列 (キュー) に登録された全ての通知が通知センターに送信されます。(要求されたモードと現在のモードが異なる場合は、要求されたモードに入ると通知が送信されます。) 実行ループは各繰り返し中に複数の呼び出しを行うことができるため、現在の呼び出しが終了しコントロールが実行ループに戻るとすぐに通知が行われるか、行われません。他の呼び出し、例えば、タイマーまたはソースの期限切れまたは他の非同期通知が配信されるなどが、最初に起こることがあります。
通常、ディスプレイのサーバーなどの高価なリソースには、NSPostASAP 送信スタイルを使用して下さい。多くのクライアントが、実行ループからの呼び出し中にウィンドウバッファ上に描画する場合、描画操作ごとにバッファをディスプレイのサーバにフラッシュするのは高価です。このような場合、各 draw... メソッドは、名前と指定されたオブジェクト、および NSPostASAP の送信スタイルで融合された "FlushTheServer" などの通知を待ち行列に入れます。結果として、これらの通知のうちの 1 つだけが実行ループの最後に急送され、ウィンドウバッファは 1 回だけフラッシュされます。
アイドル中の送信
NSPostWhenIdle スタイルでキュー (待ち行列) に入れられた通知は、実行ループが待機状態にあるときにのみ送信されます。この状態では、タイマーや他の非同期イベントなど、実行ループの入力チャネルには何もありません。NSPostWhenIdle スタイルによるキュー入れの典型的な例は、ユーザーがテキストを入力するときに発生し、プログラムはテキストのサイズをバイト数でどこかで表示します。ユーザーが入力する各文字の後ごとに、特にユーザーがすばやく入力すると、テキストフィールドのサイズを更新するのは非常に高価です (あまり有用ではありません)。この場合、プログラムは、"ChangeTheDisplayedSize" などの通知をキューに入れ、統合を有効にし、各文字の入力後に NSPostWhenIdle の送信スタイルをキューに入れます。ユーザーが入力を停止すると、実行ループは待機状態になり、ディスプレイが更新されると、キュー内の単一の "ChangeTheDisplayedSize" 通知 (統合によるため) が送信されます。終了しようとしている実行ループ (すべての入力チャネルが期限切れになったときに発生します) は待機状態ではないため、通知を送信しません。
直ちに送信
NSPostNow を使用してキューに入れられた通知は、通知センターに統合された直後に送信されます。非同期呼び出し動作を必要としない場合は、NSPostNow (または postNotification:) を使用して通知をキューに入れます。多くのプログラミング状況では、同期の動作は許容されるだけでなく、望まくもあるものです。急送後に通知センターを戻したい場合は、オブジェクトを監視して通知を受信し処理したことを確認できます。もちろん、統合によって削除するキューに同様の通知がある場合は、postNotification: を使用するのではなく、NSPostNow を使用して enqueueNotification... を使用する必要があります。
通知の統合
ある場合には、特定のイベントが少なくとも 1 回は発生したが、イベントが複数回発生しても通知を 1 回だけに限り送信したい場合は、通知を送信したいことがあります。例えば、具体的なパケット内のデータを受信したアプリケーションでは、パケットの受信時に、データの処理が必要であることを知らせる通知を送信することができます。ただし、指定された期間内に複数のパケットが到着した場合、複数の通知を送信する必要はありません。さらに、これらの通知を送信するオブジェクトは、送信メソッドがループ内で呼び出されたかどうかに関係なく、より多くのパケットが来ているかどうかを知る方法はないかもしれません。
場合によっては、イベントが発生したことを示すブール値フラグ (オブジェクトのインスタンス変数またはグローバル変数) を設定し、フラグがクリアされるまでさらなる通知の送信を抑止することもできます。しかし、これが不可能な場合は、NSNotificationCenter の動作が同期的であるため、これを直接使用することはできません。戻る前に通知が送信されるため、重複した通知を "無視する" 機会はありません。さらに、 NSNotificationCenter インスタンスには、より多くの通知が来るかどうか知る方法はありません。
したがって、通知を通知センターに送信するのではなく、適切な 統合 オプションを指定して NSNotificationQueue インスタンスに通知を追加できます。統合は、以前にキューに入れられた通知と何らかの形で類似している通知をキューから削除するプロセスです。 enqueueNotification:postingStyle:coalesceMask:forModes: メソッドの 3 番目の引数に以下の 1 つ以上の定数を指定することによって、類似した基準を指定して下さい。
NSNotificationNoCoalescing | |
NSNotificationCoalescingOnName | |
NSNotificationCoalescingOnSender |
NSNotificationCoalescingOnName および NSNotificationCoalescingOnSender 定数を使用してビット単位の OR 演算を実行して、通知名と通知オブジェクトの両方を使用した統合を指定できます。以下の例は、キューを使用して、特定のイベントループサイクル内で、MyNotificationName という名前のすべての通知が単一の通知に統合されるようにする方法を示しています。
// MyNotificationName defined globally NSString *MyNotificationName = @"MyNotification"; id object = <#The object associated with the notification#> NSNotification *myNotification = [NSNotification notificationWithName:MyNotificationName object:object] [[NSNotificationQueue defaultQueue] enqueueNotification:myNotification postingStyle:NSPostWhenIdle coalesceMask:NSNotificationCoalescingOnName forModes:nil];