Obj-C メッセージについて質問があります。
(1)それが私の主な質問です:クラスをスウィズルまたは呼び出す前に、クラスにそのスーパークラスからの実装があることを確認するにはどうすればよいですか?
ターゲット クラスでは実装されていないが、そのスーパークラスでは実装されているメソッドでメソッド スウィズリングを実行したい場合、メソッド スウィズリングの前に、このクラスがそのスーパークラスから実装されていることを確認するにはどうすればよいですか?
オブジェクトを実装していないオブジェクトにメッセージが送信されると、Obj-C ランタイムはまずその継承階層を検索して、そのスーパークラスから実装を見つけます。存在する場合、Obj-C はそれを別のディスパッチ テーブルにキャッシュして呼び出します。
このキャッシュされた実装でメソッドの入れ替えを行うことはできますか? 可能であれば、メソッドのスウィズリングまたはこのオブジェクトへのメッセージの送信の前に、キャッシュされた実装があることを確認するにはどうすればよいですか? そうでない場合、メソッドの入れ替えの前に の実装を呼び出すだけの実際の実装をこのクラスに追加するにはどうすればよいですか?super
たとえば、次のようなクラス階層があります。
@interface A : NSObject
- (void) helloWorld;
@end
@interface B : A
@end
@interface C : B
@end
@interface D : C
@end
@interface E : D
@end
そして、このような実装:
@implemenation A
- (void) helloWorld{
NSLog(@"hello world from class A");
}
@end
@implemenation B
// did not override -helloWorld
@end
@implemenation C
- (void) helloWorld{
[super helloWorld];
NSLog(@"hello world from class C");
}
@end
@implemenation D
// did not override -helloWorld
@end
@implemenation E
// did not override -helloWorld
@end
-helloWorld
実行時に の実装をクラスと正確に交換 (追加ではなく) したいだけですD
。このトリックは、次のようなスウィズル メソッドの場合、元の実装に追加のタスクを追加します。
@implemenation D (AdditionalWorkForHelloWorld)
- (void) additionalWorkForHelloWorld{
[self additionalWorkForHelloWorld];
NSLog(@"hello every one!");
}
@end
したがって、 Classまたは Class-helloWorld
のインスタンスにメッセージを送信すると、コンソールに次のメッセージが出力されます。D
E
-> hello world from class A
-> hello world from class C
-> hello every one!
いつか、クラスが次のようにD
実装し-helloWorld
た後:
@implemenation D
- (void) helloWorld{
[super helloWorld];
NSLog(@"hello world from class D");
}
@end
Classまたは Class-helloWorld
のインスタンスにメッセージを送信すると、コンソールに次のメッセージが出力されます。D
E
-> hello world from class A
-> hello world from class C
-> hello world from class D
-> hello every one!
D
このメソッド交換により、クラスが実装されているかどうかにかかわらず、追加のタスクが確実に呼び出されます-helloWorld
。
オブジェクトの の実装を呼び出す C 関数を作成する方法について質問super
しましたが、それを行うのは簡単ではないようです。super
Obj-C は、メッセージをの実装に転送するために、このキャッシュされたメカニズムをどのように実現しますか?
(2) Obj-C はどのようにsuper
キーワードを処理しますか? そしてどこsuper
ですか?
Obj-C メッセージでは、最初の 2 つの引数が隠されています:self
と_cmd
. これらは Obj-C 実装で使用できます。しかし、どこsuper
ですか?
a はのポインターsuper
と等しいか? Obj-C はどのようにキーワードを処理しますか?self
isa
super
すべての Obj-C メッセージはobjc_msgSend()
またはに変換されobjc_msgSend_stret()
ます。に送信されたすべてのメッセージは とsuper
に変換されobjc_msgSendSuper()
ますobjc_msgSendSuper_stret()
か?
前述の例では、-helloWorld
メッセージを ClassE
と ClassD
に送信E
して応答しない場合、Obj-C はメッセージを ClassC
の実装に送信します。ClassC
の実装では、その の実装を呼び出しますsuper
が、 ClassB
はそれを実装していないため、 Class に転送しA
ます。
この場合、 Class のsuper
は ClassC
である必要があるB
ため、実際には ClassB
のキャッシュされた実装を呼び出しますね。B
Classのキャッシュされた実装をスウィズルしてもいいですか?