ocメッセージ転送メカニズム
2673 ワード
一、メッセージ転送メカニズム二、動的方法決議とメッセージ転送Dynamic Method Resolution(動的方法決議)Message Forwarding(メッセージ転送)三、多重エージェントの実現
一、メッセージ転送メカニズム
OCでは、オブジェクトを呼び出す方法は、実際にはオブジェクトにメッセージを送信し、Objective-C関数呼び出しの構文をコンパイルすると、Cの関数呼び出し:objc_に翻訳されます.msgSend()は、次のようになります.
[object foo]を例にとると、 objectのisaポインタによってclass が見つかりました classでのmethod_listでfoo が見つかりました classでfooが見つからない場合は、superclassで を検索し続けます. fooという関数が見つかったら、対応する方法実装(IMP) を実行する.
fooが見つからない場合は、OCのruntimeは次の手順に従います.
二、動的方法決議とメッセージ転送
ocでは、オブジェクトが処理できないメッセージ(selectorが存在しない)をオブジェクトに送信すると、プログラムcrashが発生しますが、crashの前にocの実行時にシステムは次の2つのステップを経ます. Dynamic Method Resolution(動的メソッド決定) Message Forwarding(メッセージ転送) Dynamic Method Resolution(動的メソッド決定)
プログラムの実行時にselectorに動的に実装を提供することができます.関数の実装を追加し、YESを返すと、実行時システムはメッセージの送信プロセスを再起動し、動的に追加する方法を呼び出します.呼び出しインスタンスメソッド:-(BOOL)resolveInstanceMethod:(SEL)sel 呼び出しクラスメソッド:+(BOOL)resolveClassMethod:(SEL)sel (BOOL)resolveInstanceMethod:(SEL)sel{ if (sel == @selector(foo)) { class_addMethod([self class], sel, (IMP)dynamicMethodIMP, "V@:"); return YES; } return [super resolveInstanceMethod:sel]; } void dynamicMethodIMP(id self, SEL _cmd){ NSLog(@"%s", PRETTY_FUNCTION); }
class_addMethod(Class cls,SEL name,IMP imp,const char*types)==>動的追加方法
const char *types:
"v@:"これはvoidタイプの方法で、パラメータが入力されていません.
「i@:」これはintタイプのメソッドで、パラメータが入力されません.
"i@:@"これはintタイプのメソッドで、パラメータが入力されます.=>''i@:*''
メソッドがNOを返すと、次のステップに進みます.
Message Forwarding(メッセージ転送)先通SELルックアップ:-(id)f o r wardingTargetForSelector:(SEL)aSelector、aSelectorでメソッド名を検索し、オブジェクトを返します.ProxyDispatcher.h 後署名検索:-(NSMethodSignature)methodSignatureForSelector:(SEL)aSelector*SEL検索失敗(nilまたはselfを返す)-(NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector{NSMethodSignature methodSignature methodSignature=[super methodSignatureForSelector:aSelector];if(! methodSignature){{methodSignature=[NSMethodSignature signatureWithObjCTypes:"v@:"]; } return methodSignature; } メッセージ転送フローチャート:
一、メッセージ転送メカニズム
OCでは、オブジェクトを呼び出す方法は、実際にはオブジェクトにメッセージを送信し、Objective-C関数呼び出しの構文をコンパイルすると、Cの関数呼び出し:objc_に翻訳されます.msgSend()は、次のようになります.
[array insertObject:foo atIndex:2];
// :
objc_msgSend(array, @selector(insertObject:atIndex), foo, 2);
[object foo]を例にとると、
fooが見つからない場合は、OCのruntimeは次の手順に従います.
二、動的方法決議とメッセージ転送
ocでは、オブジェクトが処理できないメッセージ(selectorが存在しない)をオブジェクトに送信すると、プログラムcrashが発生しますが、crashの前にocの実行時にシステムは次の2つのステップを経ます.
プログラムの実行時にselectorに動的に実装を提供することができます.関数の実装を追加し、YESを返すと、実行時システムはメッセージの送信プロセスを再起動し、動的に追加する方法を呼び出します.
class_addMethod(Class cls,SEL name,IMP imp,const char*types)==>動的追加方法
const char *types:
"v@:"これはvoidタイプの方法で、パラメータが入力されていません.
「i@:」これはintタイプのメソッドで、パラメータが入力されません.
"i@:@"これはintタイプのメソッドで、パラメータが入力されます.=>''i@:*''
メソッドがNOを返すと、次のステップに進みます.
Message Forwarding(メッセージ転送)
@interface ProxyDispatcher : NSObject
- (void)Func;
@end
### ProxyDispatcher.m
- (id)forwardingTargetForSelector:(SEL)aSelector{
if (aSelector == @selector(Func)) {
return [DispatcherObject new];
}
return nil;
}
### DispatcherObject.m
- (void)Func{
NSLog(@"%s", __PRETTY_FUNCTION__);
}