8

Objective-c の内部に関するすべてのユーザーにとって非常に興味深い質問です...

だから...オブジェクトとクラスの両方NSObjectの同じ実装を返します(私が期待するように)。copyただし、オブジェクトとクラスの異なる実装を返すだけでなく、各オブジェクトには異なる実装がありNSArrayますNSMutableArrayobjectAtIndex:

次のコードがそのような動作を生成する理由を誰かが知っていますか?... (少なくとも と のクラス実装NSArrayNSMutableArray同じです:))

NSObject *obj = [[[NSObject alloc] init] autorelease];
NSLog(@"NSObject instance %@", [NSValue valueWithPointer:method_getImplementation(class_getInstanceMethod(object_getClass(obj), @selector(copy)))]);
NSLog(@"NSObject class %@", [NSValue valueWithPointer:method_getImplementation(class_getInstanceMethod([NSObject class], @selector(copy)))]);

NSArray *array = [[[NSArray alloc] init] autorelease];
NSLog(@"NSArray instance %@", [NSValue valueWithPointer:method_getImplementation(class_getInstanceMethod(object_getClass(array), @selector(objectAtIndex:)))]);
NSLog(@"NSArray class %@", [NSValue valueWithPointer:method_getImplementation(class_getInstanceMethod([NSArray class], @selector(objectAtIndex:)))]);

NSMutableArray *array1 = [[[NSMutableArray alloc] init] autorelease];
NSLog(@"NSMutableArray instance %@", [NSValue valueWithPointer:method_getImplementation(class_getInstanceMethod(object_getClass(array1), @selector(objectAtIndex:)))]);
NSLog(@"NSMutableArray class %@", [NSValue valueWithPointer:method_getImplementation(class_getInstanceMethod([NSMutableArray class], @selector(objectAtIndex:)))]);

ログ

2012-11-06 16:35:22.918 otest[71367:303] NSObject instance <c0fa7200>
2012-11-06 16:35:23.757 otest[71367:303] NSObject class <c0fa7200>
2012-11-06 16:35:30.348 otest[71367:303] NSArray instance <809a9b00>
2012-11-06 16:35:31.121 otest[71367:303] NSArray class <70bfa700>
2012-11-06 16:35:33.854 otest[71367:303] NSMutableArray instance <f05f9a00>
2012-11-06 16:35:34.824 otest[71367:303] NSMutableArray class <70bfa700>
4

1 に答える 1

26

実装の詳細、すべて。したがって、これは比較的十分な情報に基づいた推測です。

まず、16 進数値を出力するためにそのようなフープをジャンプする必要はありません。

NSLog(@"imp: %p", [NSObject instanceMethodForSelector:@selector(...)]);

クラス オブジェクトを呼び出すmethodForSelector:と、クラス メソッドの IMP が返されることに注意してください。

では、当面の質問に移ります。

Objective-C が他の一般的な OO 言語 (すべてではない) と異なる点の 1 つは、Class オブジェクトが実際には Metaclass のインスタンスであることです。そのメタクラス (実際には「メタクラス」以外の名前はありません) は、 NSObject(多かれ少なかれ) たまたまプロトコルに応答します。実際、これは一種の の派生物ですNSObject

したがって、インスタンスとクラスの特定のセレクターの実装を取得するNSObjectと、多くの場合、それらは同じではありません。これにより、Class を NSDictionary のキーにすることができることに注意してください。クラスはコピーできます。 NSObjectcopyメソッドは実行するだけでreturn [self retain];あり、もちろん、retainクラスは [ほとんどの場合] シングルトンとしてバイナリに静的にコンパイルされるため、ノーオペレーションです。技術的には、それをcopy呼び出しますcopyWithZone:(これが、ゾーンが廃止されたにもかかわらずreturn [self retain];、サブクラス化する必要がある理由です)。copyWithZone:

現在、Hot Licks が指摘しているようにNS*Array、ここ数回のリリースで内部実装の詳細が変更されたクラス クラスターです。以前は、すべてのインスタンスがすべてブリッジされNSCFArray、構成が異なっていました。最近のリリースでは、不変および可変インスタンスに対応する(sic.)__NSArrayIおよびインスタンスが表示されます。__NSArrayMほとんどの場合、それだけではありませんが、それはかなり典型的なことです。

のインスタンス メソッドobjectAtIndex:が 2 つのクラス間で異なるのは、クラス クラスタの典型です。クラスタのポイントは、プリミティブ インターフェイスの観点から実装された一連のメソッドをプリミティブ インターフェイスに提供することです (これが、ヘッダーがコア@interfaceと一連のカテゴリに分割されている理由@interfacesです。基本クラスのカテゴリは完全にコア API の用語)。

内部的には、クラスター内に公開宣言されたクラスの具体的なサブクラスがあります。これらの具体的なサブクラスは、特定のタスクに対して高度に最適化されています。この場合、不変対可変配列ストレージ (ただし、さまざまな目的に最適化された非パブリック サブクラスがさらに多く存在する可能性があります)。サブクラスは、アドバタイズされた API をオーバーライドして高度な機能を提供します。さまざまな方法の最適化されたバージョン。

したがって、2 つのクラスで見objectAtIndex:られるのは、変更可能な場合と不変な場合に最適化された の異なる実装です。

では、なぜクラス メソッドが同じなのでしょうか。良い質問。それを呼んでみましょう:

((void(*)(id,SEL,int))[[NSArray class] methodForSelector: @selector(objectAtIndex:)])([NSArray class], @selector(objectAtIndex:), 0);


2012-11-06 09:18:23.842 asdfasdf[17773:303] *** Terminating app due to uncaught
   exception 'NSInvalidArgumentException', reason: '+[NSArray objectAtIndex:]:
   unrecognized selector sent to class 0x7fff7563b1d0'

あはは!したがって、呼び出されたときに「このメソッドを認識しません」例外を発生させるメソッドの実装を求めています。実際には:

NSLog(@"%@", 
 [NSArray class] respondsToSelector:@selector(objectAtIndex:)] ? @"YES" : @"NO");

2012-11-06 09:24:31.698 asdfasdf[17839:303] NO

ランタイムが IMP を返しているように見えます。このエラーは、ターゲット オブジェクト (この場合はメタクラス インスタンス) が応答しないセレクターを使用しようとしたことを示します。これが、ターゲットがセレクターを実装しているかどうかについて疑問がある場合に備えて、事前にinstanceMethodForSelector:使用する必要があると説明している理由です。respondsToSelector:

(まあ、それは意図したよりも多くの本になりました...うまくいけば、まだ役に立ちます!)

于 2012-11-06T17:27:52.703 に答える