1

Objective C でのプログラミング、4e、第 9 章、プログラム 9.3:

#import "Square.h"
int main (int argc, char * argv[])
{
   @autoreleasepool {
      Square *mySquare = [[Square alloc] init];
      ...
      // respondsTo:
      if ( [mySquare respondsToSelector: @selector (setSide:)] == YES )
         NSLog (@"mySquare responds to setSide: method");
      ...
      if ( [Square respondsToSelector: @selector (alloc)] == YES )
         NSLog (@"Square class responds to alloc method");
      ...
   }
   return 0;
}

Q1:

-respondsToSelector:クラスメソッドではなくインスタンスメソッドなので、クラスでSquare直接使用できるのはなぜですか?

Q2:

Squareこの本には、代わりにここを使用できると書かれています[Square class]。例外的な近道ですか、それとも何か仕組みがあるのでしょうか。

どんな助けでも本当に感謝します! 前もって感謝します!

4

5 に答える 5

4

Q1:

NSObject簡単な答えは、クラスメソッドに加えて、クラスオブジェクトでルートクラスの任意のインスタンスメソッド(クラスのルートクラスが何であれ、この場合は)を呼び出すことができるということです。

より複雑な答えは、クラスオブジェクトはメタクラスのインスタンスであるということです。インスタンスメソッドはインスタンス上のメソッドであり、クラスで定義されます。クラスメソッドは、メタクラスで定義されているクラスオブジェクトのメソッドです。各クラスには独自のメタクラスがあります。メタクラスの継承は、それらのクラスの継承に従います。つまりNSString、のメタクラスはのメタクラスを継承しNSObjectます。最終的に、ルートクラスのメタクラスはルートクラスから継承します。つまりNSObject、のメタクラスはから継承しNSObjectます。そのため、NSObjectのすべてのインスタンスメソッドをクラスオブジェクトで使用できます。

Q2:

[Square class]クラスメソッドを呼び出します+class(これはとは関係ありません-class)。+class本質的には、呼び出されたものを単に返すIDメソッドです(ちょうど-self); つまり、fooがクラスオブジェクトへのポインタである場合、はと[foo class]同じfooです。

ですから+class、かなり役に立たないようです。なぜそれを使うのですか?これは、Objective-C言語の文法では、クラス名が有効な式ではないためです(Smalltalkとは異なります)。だからあなたは言うことはできませんid bar = Square;; それはコンパイルされません。文法の特殊なケースとして、メッセージ呼び出し式の受信者の代わりにクラス名が許可され、メッセージはクラスオブジェクトに送信されます。すなわち[Square something]。したがって、他の式コンテキストでクラスオブジェクトを使用する場合は、+class;のようなIDメソッドを呼び出すことにより、ラウンドアバウト方式でこれを行います。つまり[Square class]、任意の式のコンテキストで使用できる式です([Square self]これも機能しますが[Square class]、慣例により使用します。これは、と混同されるため、残念-classです)。ただ使いたかったのにSquare、しかし言語のためにできません。

あなたの場合、それはすでにメッセージ呼び出し式の受信者であるため、行う必要はありません[Square class]Squareすでにそこで働いています。

于 2012-05-31T20:39:30.553 に答える
4

The Objective-C Programming LanguageObjects、class、および Messagingから、

すべてのオブジェクト、クラス、およびインスタンスには、ランタイム システムへのインターフェイスが必要です。クラス オブジェクトとインスタンスの両方が、それらの能力について内省し、継承階層内での位置を報告できる必要があります。このインターフェースを提供するのは NSObject クラスの領域です。

NSObject メソッドを 2 回実装する必要がないように (1 回目はインスタンスのランタイム インターフェイスを提供し、2 回目はクラス オブジェクトのインターフェイスを複製するため)、<strong>クラス オブジェクトには、ルート クラスで定義されたインスタンス メソッドを実行するための特別な分配が与えられます。クラス オブジェクトがクラス メソッドで応答できないメッセージを受信すると、ランタイム システムは、応答できるルート インスタンス メソッドがあるかどうかを判断します。クラス オブジェクトが実行できる唯一のインスタンス メソッドは、ルート クラスで定義されたものであり、ジョブを実行できるクラス メソッドがない場合のみです

この場合NSObjectは、ルート クラスです。NSObjectインスタンスはすべて に準拠しているため、NSObject protocol-respondsToSelector:定義されているため、ほとんどのクラス オブジェクトは を実行できるはず-respondsToSelector:です。

于 2012-03-12T07:05:12.920 に答える
0

現在、Objective C ランタイムは、クラスを他のクラスのインスタンス オブジェクトとして実装しています。したがって、クラスは特定のインスタンス メソッドに応答します。

于 2012-03-12T09:17:57.573 に答える
0

//Q1:

-respondsToSelector: はクラス メソッドではなくインスタンス メソッドなので、Square クラスで直接使用できるのはなぜですか?//

クラスメソッドはインスタンスメソッドから呼び出すことはできない(逆もまた同様)という考えを持っているようです。それどころか、メソッド -respondsToSelector の意図はそうであるように思われます。おそらく、-class メソッドで送信者のクラスを取得し、次にクラスがセレクターに応答するかどうかを照会し、YES または NO を返すことによって行われます。よりローカライズされた例では、次のことを考慮してください。

-(void)someInstanceMethod{
     [MyCurrentClass doClassMethod]; //basic equivalent of [self doClassMethid];
}

MyCurrentClass がすべて割り当てられ、初期化されていれば、Objective-C で完全に有効です。

//Q2:

[Square クラス] の代わりに、ここで Square を使用できると書かれています。それは例外的な近道にすぎないのでしょうか、それとも何かメカニズムがあるのでしょうか?//

-class をクラスに送信するのは完全に冗長です! これはほとんど意味がなく、余分な不要なコードです。-class は、受信者のクラスがインスタンスであるか Class オブジェクトであるかに関係なく、単にクエリを実行します。

于 2012-03-12T05:43:22.393 に答える
-1

NSObject.m から直接抽出した実際の実装は次のとおりです。

- (BOOL)respondsToSelector:(SEL)aSelector {
        PF_HELLO("")
        return class_respondsToSelector( isa, aSelector );
}

なぜPF_HELLO("")そこにあるのかはわかりませんが、ご覧のとおり、文字通り、ランタイムでクラスに「ねえ、この isa [インスタンス] の aSelector と呼ばれるメソッドはありますか?」と尋ねています。

また、Objective-C では、クラス メソッドもインスタンスに属しますが、優先順位は低くなります (クラス メソッドと同じ名前のインスタンス メソッドは、クラス メソッドの前に呼び出されます)。

Objective-C の動的型付けのもう 1 つの側面は、id型が実際には次のように宣言されていることです。

typedef struct objc_class *Class;
typedef struct objc_object {
    Class isa;
} *id;

したがって、インスタンス オブジェクトは実際にはクラス ポインターです。これは、 -respondsToSelector メッセージがインスタンス タイプのクラスにも送信されることを意味します。あなたの場合、それは -respondsToSelector が最初に objc_class に行くことを意味します。

テストケース(libFoundationから直接)では、私の答えは次のように要約されます。

Test *tst = [Test new];

    fail_unless([tst respondsToSelector:@selector(testInstanceMethod)], "-[Test respondsToSelector:] returned NO for a valid instance method (testInstanceMethod).");
    fail_if([tst respondsToSelector:@selector(testClassMethod)], "-[Test respondsToSelector:] returned YES for a class method (testInstanceMethod).");
    fail_unless([Test respondsToSelector:@selector(testClassMethod)], "+[Test respondsToSelector:] returned NO for a valid class method (testClassMethod).");
    fail_if([Test respondsToSelector:@selector(testInstanceMethod)], "+[Test respondsToSelector:] returned YES for an instance method (testInstanceMethod).");
    fail_unless([tst respondsToSelector:@selector(init)], "-[Test respondsToSelector:] returned NO for an inherited instance method (-[NSObject init].");
    fail_unless([Test respondsToSelector:@selector(alloc)], "+[Test respondsToSelector:] returned NO for an inherited class method (+[NSObject alloc]).");

    [tst release];
于 2012-03-12T06:27:11.160 に答える