クラスインターフェイスの宣言は、コンパイラディレクティブ @interfaceで始まり、ディレクティブ @endで終わります(コンパイラに対するObjective-Cのディレクティブはすべて「@」で始まります)。
@interface ClassName :ItsSuperclass |
{ |
instance variable declarations |
} |
method declarations |
@end |
宣言の1行目では、新しいクラス名を指定し、それをスーパークラスにリンクします。継承で説明したように、スーパークラスによって継承階層における新しいクラスの位置が決まります。コロンとスーパークラス名を省略すると、新しいクラスはルートクラス(NSObjectクラスのライバル)として宣言されます。
クラス宣言の最初の部分に続いて、インスタンス変数の宣言が中括弧で囲まれています。インスタンス変数は、クラスの各インスタンスの一部をなすデータ構造です。次に、Rectangleクラスで宣言できるインスタンス変数の一部を示します。
float width; |
float height; |
BOOL filled; |
NSColor *fillColor; |
次に、インスタンス変数を囲んだ中括弧の後から、クラス宣言の終わりまでの間に、クラスのメソッドを宣言します。クラスオブジェクトに使用されるメソッドの名前、つまりクラスメソッドの前にはプラス記号を付けます。
+ alloc; |
クラスのインスタンスが使用できるメソッド、つまりインスタンスメソッドの前にはマイナス記号を付けます。
- (void)display; |
一般的な方法ではありませんが、クラスメソッドとインスタンスメソッドを同じ名前で定義することができます。メソッドに、インスタンス変数と同じ名前を付けることもできます。これが一般的なのは、特にメソッドが変数の値を返す場合です。たとえば、Circleがradiusインスタンス変数に一致するradiusメソッドを持つことができます。
メソッドの戻り型は、標準Cの型キャストの構文を使って宣言します。
- (float)radius; |
- (void)setRadius:(float)aRadius; |
戻り型や引数型を明示的に宣言しないと、メソッドやメッセージのデフォルト型、idと見なされます。前述のallocメソッドはidを返します。
複数の引数がある場合は、メソッド名の中でコロンの後に引数を宣言します。引数は、メッセージの場合と同様に、宣言でも名前が区切られます。たとえば、
- (void)setWidth:(float)width height:(float)height; |
可変引数を持つメソッドは、関数と同様に、コンマと省略記号を使って引数を宣言します。
- makeGroup:group, ...; |
インターフェイスのインポート
他のクラスの参照
インターフェイスの役割
インターフェイスファイルは、当該クラスインターフェイスに依存するすべてのソースモジュールにインクルードする必要があります。対象となるソースモジュールとしては、当該クラスのインスタンスを作成したり、クラスに宣言したメソッドを呼び出すメッセージを送信したり、クラスで宣言したインスタンス変数を記述するモジュールがあります。インターフェイスは、通常、#importディレクティブでインクルードされます。
#import "Rectangle.h" |
このディレクティブは#includeと同じですが、同じファイルが2回以上はインクルードされないことが保証されています。そのため、使用が推奨されており、すべてのObjective-C関連ドキュメントのコード例の中で、#includeの代わりに使用されています。
クラス定義が派生クラスの定義に基づいて構築されることを反映して、インターフェイスファイルはスーパークラスのインターフェイスをインポートすることで始まります。
#import "ItsSuperclass.h" |
@interface ClassName :ItsSuperclass |
{ |
instance variable declarations |
} |
method declarations |
@end |
この規則は、あらゆるインターフェイスファイルが、すべての派生クラスのインターフェイスファイルを間接的にインクルードすることを意味します。ソースモジュールがあるクラスインターフェイスをインポートすると、そのクラスのベースとなっている継承階層全体のインターフェイスが得られます。
スーパークラスをサポートするprecomp(プリコンパイルされたヘッダ)がある場合は、代わりにprecompをインポートすることもできます。
インターフェイスファイルでクラスを宣言すると、そのスーパークラスをインポートすることで、NSObjectからスーパークラスに至るまで、すべての派生クラスの宣言を暗黙のうちに含みます。インターフェイスがその階層以外のクラスを記述している場合は、それらを明示的にインポートするか、@classディレクティブで宣言する必要があります。
@class Rectangle, Circle; |
このディレクティブは、「Rectangle」と「Circle」がクラス名であることをコンパイラに知らせるだけです。インターフェイスファイルをインポートするものではありません。
インスタンス変数、戻り値、および引数を静的に型定義するときに、インターフェイスファイルにクラス名を記述します。たとえば、次の宣言をご覧ください。
- (void)setPrimaryColor:(NSColor *)aColor; |
この宣言には、NSColorクラスが記述されています。
このような宣言では単にクラス名を型として使用し、クラスインターフェイスの詳細(メソッドとインスタンス変数)には依存していないため、@classディレクティブはコンパイラにとっては予測されることの十分な予告となります。しかし、クラスのインターフェイスを実際に使用する場面では(インスタンスの作成、メッセージの送信)、クラスインターフェイスをインポートする必要があります。通常、インターフェイスファイルで@classを使ってクラスを宣言し、(それらのクラスのインスタンスを作成したり、メッセージを送信する必要があるため)対応する実装ファイルでそれらのインターフェイスをインポートします。
@classディレクティブは、コンパイラとリンカによって参照されるコードの量を最小限に抑えるため、クラス名の前方宣言を行う最も簡潔な方法です。簡潔であるため、他のファイルをインポートするファイルのインポートに伴う潜在的な問題が回避されます。たとえば、あるクラスが別のクラスの静的に型定義されたインスタンス変数を宣言していて、それぞれのインターフェイスファイルが互いをインポートすると、どちらのクラスも正しくコンパイルされない可能性があります。
インターフェイスファイルの目的は、新しいクラスを他のソースモジュール(および他のプログラマ)に対して宣言することです。インターフェイスファイルには、クラスを使用するのに必要なすべての情報が含まれています(いくらか文書化されていればプログラマにも歓迎されるでしょう)。
インターフェイスファイルは、クラスが継承階層にどのように結び付いていて、どのようなクラスが他に必要となるか(継承するか、クラスのどこかで参照するか)をユーザに知らせます。
また、インターフェイスファイルはオブジェクトに含まれているインスタンス変数をコンパイラに知らせ、サブクラスが継承している変数をプログラマに知らせます。インスタンス変数は、インターフェイスではなくクラスの実装の問題と考えるのが最も自然ですが、それでもやはり、インターフェイスファイルで宣言する必要があります。これは、コンパイラが、オブジェクトが定義されている場所だけでなく、オブジェクトが使用される場所でもオブジェクトの構造を認識している必要があるからです。しかし、一般にプログラマは、サブクラスを定義する場合を除いて、使用するクラスのインスタンス変数を無視することができます。
最後に、メソッド宣言のリストを通して、インターフェイスファイルは他のモジュールに、どのようなメッセージをクラスオブジェクトとクラスインスタンスに送信できるかを知らせます。クラス定義の外部で使用できるすべてのメソッドを、インターフェイスファイルで宣言します。クラス実装の内部で使用するメソッドは省略できます。
Last updated: 2007-10-31