|
|
Log In | Not a Member? |
Contact ADC |
| < 前ページ次ページ > |
Objective-Cでは、メソッドを実行するオブジェクトを参照するためにメソッド定義内で使用できる2つのキーワード、selfとsuperが提供されています。
たとえば、操作対象となるすべてのオブジェクトの座標を変更する必要がある、repositionメソッドを定義するとします。そのメソッドは、変更を行うsetOrigin::メソッドを呼び出すことができます。必要なのは、repositionメッセージ自体の送信先となった同じオブジェクトにsetOrigin::メッセージを送信することだけです。位置変更コードを記述する際には、そのオブジェクトをselfまたはsuperのいずれかとして参照することができます。repositionメソッドはどちらも読み取ることができます。
- reposition |
{ |
... |
[self setOrigin:someX :someY]; |
... |
} |
または
- reposition |
{ |
... |
[super setOrigin:someX :someY]; |
... |
} |
この場合、どのようなオブジェクトであっても、selfとsuperはどちらもrepositionメッセージを受信するオブジェクトを参照します。ただし、この2つのキーワードはまったく異なるものです。selfは、メッセージングルーチンがすべてのメソッドに渡す隠し引数の1つであり、インスタンス変数の名前と同じように、メソッド実装内で自由に使用できるローカル変数です。superは、メッセージ式でレシーバとしてのみselfの代わりに使用できるキーワードです。レシーバーから見ると、2つのキーワードは、主にメッセージング処理に与える影響が異なります。
selfは受信側オブジェクトのクラスのディスパッチテーブルから始まり、通常の方法でメソッド実装を検索します。上記の例では、再配置メッセージを受信するオブジェクトのクラスから検索を始めます。
superは、まったく異なる場所でメソッド実装の検索を開始します。検索は、superが出現するメソッドを定義する、クラスのスーパークラスから始まります。上記の例では、再配置が定義されるクラスのスーパークラスから検索を始めます。
どこでsuperがメッセージを受信しても、コンパイラはobjc_msgSend関数の代わりに別のメッセージングルーチンを使用します。代替ルーチンは、メッセージを受信するオブジェクトのクラスではなく、定義クラスのスーパークラス、つまりsuperにメッセージを送信するクラスのスーパークラスを直接参照します。
selfとsuperの違いは、3つのクラスの階層で明確になります。たとえば、Lowというクラスに属するオブジェクトを作成するとします。LowのスーパークラスはMidで、MidのスーパークラスはHighです。3つのクラスすべてでnegotiateというメソッドを定義し、さまざまな用途に使用します。さらに、MidではmakeLastingPeaceという高度なメソッドを定義しますが、これはnegotiateメソッドも必要とします。図 7-2にこれを図示します。
ここでmakeLastingPeaceメソッドを実行するために、Lowオブジェクトにメッセージを送信します。すると、makeLastingPeaceは同じLowオブジェクトにnegotiateメッセージを送信します。ソースコードの中でメッセージの送信対象オブジェクトをselfと呼ぶ場合には、次のようになります。
- makeLastingPeace |
{ |
[self negotiate]; |
... |
} |
メッセージングルーチンは、selfの実際のクラスであるLowに定義されているバージョンのnegotiateを探します。しかし、Midのソースコードで送信対象のオブジェクトをsuperと呼ぶ場合には、次のようになります。
- makeLastingPeace |
{ |
[super negotiate]; |
... |
} |
メッセージングルーチンは、Highで定義されているバージョンのnegotiateを探します。makeLastingPeaceはMidで定義されているため、メッセージングルーチンは受信側オブジェクトのクラス(Low)を無視して、Midのスーパークラスにスキップします。どちらのメッセージも、Midバージョンのnegotiateを探しません。
この例に示すように、superは別のメソッドをオーバーライドするメソッドをバイパスする手段を提供します。これによりここでは、makeLastingPeaceは、元のHighバージョンのnegotiateを再定義するMidバージョンを回避することができました。
Midバージョンのnegotiateに到達できないのは欠陥のように見えるかもしれませんが、このような状況ではそれを回避するほうが適切です。
Lowクラスの作成者が意図的にMidバージョンのnegotiateをオーバーライドして、Lowクラス(およびそのサブクラス)のインスタンスが、再定義されたバージョンのメソッドを代わりに呼び出すようにしています。Lowの設計者は、Lowオブジェクトに継承メソッドを実行させないようにしたわけです。
superにメッセージを送信することで、MidのmakeLastingPeaceメソッドの作成者は、Midバージョンのnegotiate(およびMidを継承するLowなどのクラスで定義するバージョン)を意図的にスキップして、Highクラスに定義されているバージョンを実行するようにしました。Midの設計者は、negotiateのHighバージョンだけを使用するようにしたいわけです。
それでもMidバージョンのnegotiateを使用することはできますが、そのためにはMidインスタンスに直接メッセージを送信する必要があります。
superへのメッセージにより、メソッド実装を複数のクラスに分散することができます。既存のメソッドをオーバーライドして変更や追加を行う一方で、元のメソッドをその変更に組む込むことができます。
- negotiate |
{ |
... |
return [super negotiate]; |
} |
処理によっては、継承階層の各クラスで作業の一部を行い、残りの作業についてはメッセージをsuperに渡して処理するメソッドを実装することができます。新たに割り当てられたインスタンスを初期化するinitメソッドは、このように動作するように設計されています。それぞれのinitメソッドは、クラスに定義されているインスタンス変数を初期化する役割を持っています。しかし、初期化の前に、initメッセージをsuperに送信して、継承元のクラスにインスタンス変数を初期化させます。initの各バージョンがこの手続きに従うため、クラスは継承の順序に従ってインスタンス変数を初期化することになります。
- (id)init |
{ |
[super init]; |
... |
} |
また、中核的な機能をスーパークラスで定義された1つのメソッドに集中させ、サブクラスにおいてsuperへのメッセージを使用してそのメソッドを組み込むこともできます。たとえば、インスタンスを作成するすべてのクラスメソッドは、新しいオブジェクトにデータ記憶域を割り当て、isaポインタをクラス構造で初期化する必要があります。これは、通常、NSObjectクラスに定義されているallocおよびallocWithZone:メソッドに委ねられます。別のクラスでこれらのメソッドをオーバーライドする場合も(まれなケース)、そのメソッドでメッセージをsuperに送信することによって基本機能を利用することができます。
superは実行するメソッドの検索を始める場所をコンパイラに伝える単なるフラグで、メッセージのレシーバとしてのみ使用します。しかし、selfは変数名で、いろいろな方法で使用でき、新しい値を代入することもできます。
クラスメソッドの定義では、まさにそうすることがよくあります。クラスメソッドは多くの場合、クラスオブジェクトではなく、クラスのインスタンスを対象としています。たとえば、多くのクラスメソッドがインスタンスの割り当てと初期化を結合し、多くの場合、同時にインスタンス変数値も設定します。このようなメソッドでは、インスタンスメソッドの場合と同様に、新たに割り当てられたインスタンスにメッセージを送信して、selfインスタンスを呼び出すことも考えられます。しかし、これはエラーになります。selfとsuperは、どちらも受信側オブジェクト(メソッドを実行するように指示するメッセージを取得するオブジェクト)を参照します。インスタンスメソッド内ではselfはインスタンスを参照しますが、クラスメソッド内でselfはクラスオブジェクトを参照します。次の例は、してはいけないことを示します。
+ (Rectangle *)rectangleOfColor:(NSColor *) color |
{ |
self = [[Rectangle alloc] init]; // だめ |
[self setColor:color]; |
return [self autorelease]; |
} |
混乱を避けるために、通常はクラスメソッド内のインスタンスを参照するとき、selfではなく、変数を使用するほうが適切です。
+ (id)rectangleOfColor:(NSColor *)color |
{ |
id newInstance = [[Rectangle alloc] init]; // よい |
[newInstance setColor:color]; |
return [newInstance autorelease]; |
} |
実際、クラスメソッドの中でクラスにallocメッセージを送信するよりも、allocをselfに送信するほうが有効です。こうしておけば、クラスをサブクラス化し、サブクラスがrectangleOfColor:メッセージを受信した場合、返されるインスタンスはそのサブクラスと同じ型になります(たとえば、NSArrayのarrayメソッドは、NSMutableArrayによって継承されます)。
+ (id)rectangleOfColor:(NSColor *)color |
{ |
id newInstance = [[self alloc] init]; // 最良 |
[newInstance setColor:color]; |
return [newInstance autorelease]; |
} |
オブジェクト割り当ての詳細については、オブジェクトの割り当てと初期化を参照してください。
| < 前ページ次ページ > |
Last updated: 2007-10-31
|
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 |