Apple Developer Connection
Advanced Search
Member Login Log In | Not a Member? Contact ADC

< 前ページ次ページ >

selfとsuperに対するメッセージ

Objective-Cでは、メソッドを実行するオブジェクトを参照するためにメソッド定義内で使用できる2つのキーワード、selfsuperが提供されています。

たとえば、操作対象となるすべてのオブジェクトの座標を変更する必要がある、repositionメソッドを定義するとします。そのメソッドは、変更を行うsetOrigin::メソッドを呼び出すことができます。必要なのは、repositionメッセージ自体の送信先となった同じオブジェクトにsetOrigin::メッセージを送信することだけです。位置変更コードを記述する際には、そのオブジェクトをselfまたはsuperのいずれかとして参照することができます。repositionメソッドはどちらも読み取ることができます。

- reposition
{
    ...
    [self setOrigin:someX :someY];
    ...
}

または

- reposition
{
    ...
    [super setOrigin:someX :someY];
    ...
}

この場合、どのようなオブジェクトであっても、selfsuperはどちらもrepositionメッセージを受信するオブジェクトを参照します。ただし、この2つのキーワードはまったく異なるものです。selfは、メッセージングルーチンがすべてのメソッドに渡す隠し引数の1つであり、インスタンス変数の名前と同じように、メソッド実装内で自由に使用できるローカル変数です。superは、メッセージ式でレシーバとしてのみselfの代わりに使用できるキーワードです。レシーバーから見ると、2つのキーワードは、主にメッセージング処理に与える影響が異なります。

どこでsuperがメッセージを受信しても、コンパイラはobjc_msgSend関数の代わりに別のメッセージングルーチンを使用します。代替ルーチンは、メッセージを受信するオブジェクトのクラスではなく、定義クラスのスーパークラス、つまりsuperにメッセージを送信するクラスのスーパークラスを直接参照します。

このセクションの内容:


superの使用
selfの再定義


selfsuperの違いは、3つのクラスの階層で明確になります。たとえば、Lowというクラスに属するオブジェクトを作成するとします。LowのスーパークラスはMidで、MidのスーパークラスはHighです。3つのクラスすべてでnegotiateというメソッドを定義し、さまざまな用途に使用します。さらに、MidではmakeLastingPeaceという高度なメソッドを定義しますが、これはnegotiateメソッドも必要とします。図 7-2にこれを図示します。


図 7-2  High、Mid、Low

High、Mid、Low

ここで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に到達できないのは欠陥のように見えるかもしれませんが、このような状況ではそれを回避するほうが適切です。

それでもMidバージョンのnegotiateを使用することはできますが、そのためにはMidインスタンスに直接メッセージを送信する必要があります。

superの使用

superへのメッセージにより、メソッド実装を複数のクラスに分散することができます。既存のメソッドをオーバーライドして変更や追加を行う一方で、元のメソッドをその変更に組む込むことができます。

- negotiate
{
    ...
    return [super negotiate];
}

処理によっては、継承階層の各クラスで作業の一部を行い、残りの作業についてはメッセージをsuperに渡して処理するメソッドを実装することができます。新たに割り当てられたインスタンスを初期化するinitメソッドは、このように動作するように設計されています。それぞれのinitメソッドは、クラスに定義されているインスタンス変数を初期化する役割を持っています。しかし、初期化の前に、initメッセージをsuperに送信して、継承元のクラスにインスタンス変数を初期化させます。initの各バージョンがこの手続きに従うため、クラスは継承の順序に従ってインスタンス変数を初期化することになります。

- (id)init
{
    [super init];
    ...
}

また、中核的な機能をスーパークラスで定義された1つのメソッドに集中させ、サブクラスにおいてsuperへのメッセージを使用してそのメソッドを組み込むこともできます。たとえば、インスタンスを作成するすべてのクラスメソッドは、新しいオブジェクトにデータ記憶域を割り当て、isaポインタをクラス構造で初期化する必要があります。これは、通常、NSObjectクラスに定義されているallocおよびallocWithZone:メソッドに委ねられます。別のクラスでこれらのメソッドをオーバーライドする場合も(まれなケース)、そのメソッドでメッセージをsuperに送信することによって基本機能を利用することができます。

selfの再定義

superは実行するメソッドの検索を始める場所をコンパイラに伝える単なるフラグで、メッセージのレシーバとしてのみ使用します。‏しかし、selfは変数名で、いろいろな方法で使用でき、新しい値を代入することもできます。

クラスメソッドの定義では、まさにそうすることがよくあります。クラスメソッドは多くの場合、クラスオブジェクトではなく、クラスのインスタンスを対象としています。たとえば、多くのクラスメソッドがインスタンスの割り当てと初期化を結合し、多くの場合、同時にインスタンス変数値も設定します。このようなメソッドでは、インスタンスメソッドの場合と同様に、新たに割り当てられたインスタンスにメッセージを送信して、selfインスタンスを呼び出すことも考えられます。しかし、これはエラーになります。selfsuperは、どちらも受信側オブジェクト(メソッドを実行するように指示するメッセージを取得するオブジェクト)を参照します。インスタンスメソッド内では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メッセージを送信するよりも、allocselfに送信するほうが有効です。こうしておけば、クラスをサブクラス化し、サブクラスがrectangleOfColor:メッセージを受信した場合、返されるインスタンスはそのサブクラスと同じ型になります(たとえば、NSArrayarrayメソッドは、NSMutableArrayによって継承されます)。

+ (id)rectangleOfColor:(NSColor *)color
{
    id newInstance = [[self alloc] init]; // 最良
    [newInstance setColor:color];
    return [newInstance autorelease];
}

オブジェクト割り当ての詳細については、オブジェクトの割り当てと初期化を参照してください。



< 前ページ次ページ >


Last updated: 2007-10-31




Did this document help you?
Yes: Tell us what works for you.

It’s good, but: Report typos, inaccuracies, and so forth.

It wasn’t helpful: Tell us what would have helped.
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