【コラム】
前回はObserverパターンの紹介を行った。今回は、この実例をCocoaの名から探してみよう。
取り上げるのは、NSNotificationクラスである。通知と呼ばれるメカニズムを提供するものだ。
NSNotificationおよびそれに関連するいくつかのクラスは、イベント等の通知を行うクラスだ。Cocoaのフレームワーク内で広く使われている。
いくつかのクラスが絡んでくるので、それらを紹介しよう。前回、Observerパターンでは、ObserverとSubjectという、2つの役割が登場することを説明した。これをNSNotificationに当てはめると、SubjectはNSNotificationCenterというクラスになる。このクラスの中で、Observerクラスの参照を保持しておくのが、NSNotificationQueueというクラスだ。
これに対して、Observerとなる特定のクラスはない。さらに、通知を受け取るために、Observerとなるクラスが実装すべきメソッドというのも定義されていない。ではどうなっているかというと、NSNotificationCenterに登録をする際に、通知を受け取るオブジェクトと、呼び出すセレクタのペアを指定するのだ。これにより、どんなクラスのどんなメソッドでもObserverとして利用できる。非常にObjective-Cらしいやり方だ。(参考: ターゲット/アクションパラダイム)
もう一つ、NSNotificationというクラスが登場する。これは、通知する内容をカプセル化するためのクラスだ。このクラスには以下のメソッドがあり、通知に関する情報を取り出すことが出来る。
- (NSString*)name;
- (id)object;
- (NSDictionary*)userInfo;
nameは、この通知の名前。objectは、主にこの通知を送ったオブジェクトになる。つまり、イベントの発信先ということだ。userInfoは、辞書であるNSDictionary型の変数で、通知の種類ごとに好きな情報を入れることが出来る。
このように、通知先の指定、通知する内容に関しては、非常に拡張性が高いと言えるだろう。
この3つのクラスと、通知を受け取るクラスの関係を図示すると、以下のようになるだろう。
|
では、NSNotificationを使ってみよう。ここでは、カスタムの通知を行ってみる。
まず、通知の名前を決めよう。たとえば、ユーザが改行キーを押した、というイベントを通知するとしよう。これを、SpaceKeyPressedという名前にする。名前は、文字列を表すNSString型になる。
次に、通知を受け取るオブジェクトの登録を行う。Observerデザインパターンの言葉を使えば、ObserverをSubjectに登録する、ということになる。
Subjectとなるのは、NSNotificationCenterクラスだ。NSNotificationCenterは、インスタンスが1つしかない、Singletonパターンのクラスになる。この1つだけのインスタンスを取り出すメソッドは、defaultCenterというメソッドだ。
Observerとなるクラスは、なんでもいい。ここでは呼び出し元のクラスを使おう。通知を受け取るメソッドも、これまた何でもいい。ただし、1つだけ制限があって、NSNotification型の変数を1つ引数として取る必要がある。
これらを踏まえて、次のようなコードで登録を行うことが出来る。
// NSNotificationCenterを取得する
NSNotifcationCenter* center;
center = [NSNotificationCenter defaultCenter];
// Observerとして登録する
[center addObserver:self selector:@selector(spaceKeyPressed:)
name:@"SpaceKeyPressed" object:nil];
登録を行うメソッドは、addObserver:selector:name:object:というものだ。引数は4つとる。第一引数は通知を受け取るオブジェクト、第二引数は呼び出されるメソッドのセレクタとなる。第三引数は、通知の名前。そして第四引数では、通知を送るオブジェクトを指定することが出来る。もし第四引数に何らかのオブジェクトが指定してあれば、そのオブジェクトから送られた通知のみ、受け取ることが出来る。nilの場合は、すべてのオブジェクトからの通知を受け取ることになる。
最後に、通知を送る側を見てみよう。通知を送るときは、まずNSNotificationのインスタンスを作る。そして、NSNotificationCenterのメソッドを使って、通知するのだ。
// NSNotificationを作成する
NSNotification* notification;
notification = [NSNotification notificationWithName:@"SpaceKeyPressed"
object:self userInfo:nil];
// NSNotificationCenterを取得する
NSNotifcationCenter* center;
center = [NSNotificationCenter defaultCenter];
// 通知を行う
[center postNotification:notification];
まず、NSNotificationのインスタンスを作っている。引数として、通知の名前、オブジェクト、ユーザ情報の3つを指定出来る。今回は、ユーザ情報は特に必要ないので、nilを指定した。
そして、これを通知する。使うのは、postNotification:というメソッドだ。引数に、先ほど作ったNSNotificationのインスタンスを渡せばいい。
これで通知が行われる。先ほど登録した、spaceKeyPressed:メソッドが呼び出されるはずだ。
これがCocoaのNSNotificationの仕組みだ。これを、Observerデザインパターンとして評価してみよう。
まず、1対多の通知を実現している。これは、NSNotificationCenterが、複数のObserverを登録出来るからだ。ここに、NSNotificationQueueを使っている。
また、ObserverとSubjectの結びつきが弱い、と言うことが出来る。なぜなら、通知の種類の指定に文字列を使っている。さらに、通知を受け取るメソッドが、オブジェクトとセレクタの組で指定しているので、Subject側のいかなる条件にも左右されない。
もし、Observerとなるクラスが通知を受け取るために、あるクラスを継承する必要があったり、ある特定のメソッドを実装しなくてはいけない、となると、ObserverとSubjectの結びつきは強くなる。強い結びつきは、再利用可能なソースコードを作ろうとするときに、不利に働くことが多い。なぜなら、Subjectが変更されるたびにObserverも再コンパイルやソースコードの書き直しを強いられるし、なによりSubjectがないとObserverのコンパイルすら出来ないことも多い。
Objective-Cは、メソッドをセレクタで指定することで、結びつきをとても弱くすることに成功していると言えるだろう。このため、NSNotificationの仕組みは、Mac OS Xの多くのフレームワークで、気軽に使われている。アプリケーションの実行中は非常に多くの通知が飛び交い、それでいてバージョンアップを繰り返し変更が積み重なっても、破綻する恐れはない。基礎的な仕組みとして、充分な実用性があるパターンだ。
| 理研、脳・脊髄形成に必要な神経板湾曲の仕組みを解明 [20:16 5/25] |
| 京大、「慢性閉塞性肺疾患」患者の労作時呼吸困難は鍼治療が有効と実証 [20:08 5/25] |
| 120Hz SHVカメラ用イメージセンサーを使った撮像装置 - SHVフルスペック化へ [18:10 5/25] |
| 京大、視覚による物体認知は前頭前野からのトップダウン信号が重要と確認 [17:45 5/25] |
| 製品数の拡大だけでなくBCPの展開なども含めた総合力で事業の強化を図るTI [17:25 5/25] |
|
[9nine]制服姿見納め? セーラー服で登場も川島海荷「4人はコスプレ」 [19:15 5/27] エンタメ |
|
「NO.6」4巻は書き下ろしドラマCD付、木乃のサイン会も [18:49 5/27] ホビー |
|
[今週の新刊]マンガ大賞3回ノミネート「アイアムアヒーロー」 カープ愛「球場ラヴァーズ」も [18:33 5/27] ホビー |
|
「ゆりてつ」サイン会は作者と都電に揺られるツアー仕立て [17:45 5/27] ホビー |
|
【ネタバレもありの徹底解明コラム】『サザエさん』タマの意外な事実 [17:30 5/27] ホビー |
4つの診断で、自分の適性を見つめなおそう!
働くこと・挑戦し続けることへの思いを綴ったインタビュー
あなたにピッタリのアドバイスを読むことができます。
転職に必要な情報が収集できます
企業からアプローチのメッセージが届きます。