【コラム】

ダイナミックObjective-C

10 非形式プロトコル - もう1つのプロトコル

木下誠  [2005/10/12]

前回は、Objective-Cのプロトコルについて説明したが、その利点としてプロセス間通信の抑制という点を挙げた。だが、プロトコルは、もう一つの側面である「オブジェクトの振る舞いを表すメソッドの集合」をするもの、という文脈で語られることが多い。この説明を後回しにしたのは、この機能は「もう1つのプロトコル」で実現されることが多いからだ。今回は、このことを説明しよう。

非形式プロトコル

前回説明したように、プロトコルは「@protocol」という、特別な文法を導入している。だが、メソッドの集合を宣言するだけなれば、わざわざ新しい文法を使う必要はない。カテゴリを使えばよい。ただし、ちょっとコツがいる。Objective-Cのルートクラスである、NSObjectのカテゴリとして宣言するのだ。

実際の例を紹介しよう。Cocoaでは、テーブルビューを表示するために、NSTableViewというクラスがある。NSTableViewでは、テーブルに表示するデータを、データソースとなるオブジェクトから取得する。データソースのために必要なメソッドは、NSTableDataSourceプロトコルで定義されている。次の宣言だ。

@interface NSObject(NSTableDataSource)
- (int)numberOfRowsInTableView:(NSTableView*)tableView;
- (id)tableView:(NSTableView*)tableView objectValueForTableColumn:(NSTableColumn*)tableColumn row:(int)row;
@end

これは、テーブルのデータソースのためのメソッドの集合なので、機能の意味としてはプロトコルだ。だが、@protocol指示子は使わずに、NSObjectのカテゴリとして宣言されている。これを非形式プロトコルと呼ぶ。@protocolによるものは、特に区別するために形式プロトコルと呼ぶこともある。

非形式プロトコルの使い方

では、非形式プロトコルを、あるクラスに準拠させるときのことを考えてみよう。とはいっても、実は何も特別なことはないのだが。

まず、非形式プロトコルを実装するとき、特別な宣言は何もいらない。なぜならば、ルートクラスであるNSObjectで、すでに宣言されているのだから。いきなり、必要なメソッドを実装してしまえばいい。

ということは、あるクラスが非形式プロトコルに準拠しているかどうか確かめる手段は、メソッドの実装を調べるためのrespondsToSelector:を使うしかないのである。形式プロトコルの場合は、conformsToProtocol:というメソッドで調査できた。非形式プロトコルの場合には、これに対応するものはない。

だから、コンパイラによる実装漏れのチェックなどは、もちろんない。たとえば、あるクラスでNSTableDataSourceプロトコルを実装する、と決めても、そのための宣言はなにもないのだから、実際にそのメソッドを実装したかどうかは、プログラマが責任を持つことになる。あとは、実行時にrespondsToSelector:を使って調べるだけである。

つまり、ただ単なるメソッドの集合であり、言語によるサポートはまったくといっていいほどない。

非形式プロトコルの利点

言語仕様という点から見ると、まったくつまらない非形式プロトコルだが、もちろん存在理由がある。いや、実際のところ、Cocoaで提供されているプロトコルを調べると、形式プロトコルよりも非形式プロトコルの方が圧倒的に多いのである。文法的にはなんのサポートもない、非形式プロコトルが好まれる理由は何であろうか?

非形式プロトコルが適しているものとして、宣言されているメソッドの実装が任意である場合、が挙げられる。つまり、すべてのメソッドを実装する必要がない場合だ。具体的な例としては、デリゲートがある。

デリゲートは、日本語では委譲と訳される、あるクラスの動作の「判断」を、外部のオブジェクトにゆだねるための機構だ。たとえば、Cocoaではウィンドウを表すNSWindowというクラスがある。このクラスは基本的な動作、たとえばウィンドウの移動や、ウィンドウのリサイズ、を行う前に、デリゲートに実行してもいいかどうか問い合わせてくる。デリゲートは、アプリケーションの状況に応じて、実行を許可したり、リサイズの大きさを特別な値に変更したりする。

このような、デリゲートで使われるメソッドは、非形式プロトコルで宣言されている。デリゲートのメソッドは、結構な数になることが多い。だがその中の、1つか2つのメソッドしか使わないこともよくある。このような場合、形式プロトコルを使うと、宣言されているすべてのメソッドを実装することが求められるので、中身が空のメソッドが多数できてしまう。非形式プロトコルの方が適切だ。

次回はこの、非形式プロトコルによるデリゲートについて、掘り下げてみよう。

    新着記事

    特設サイトの情報

    人気記事

    一覧

    イチオシ記事

    新着記事

    特別企画

    一覧