ocメッセージ転送メカニズム

2673 ワード

一、メッセージ転送メカニズム二、動的方法決議とメッセージ転送Dynamic Method Resolution(動的方法決議)Message Forwarding(メッセージ転送)三、多重エージェントの実現
一、メッセージ転送メカニズム
OCでは、オブジェクトを呼び出す方法は、実際にはオブジェクトにメッセージを送信し、Objective-C関数呼び出しの構文をコンパイルすると、Cの関数呼び出し:objc_に翻訳されます.msgSend()は、次のようになります.
[array insertObject:foo atIndex:2];
//     :
objc_msgSend(array, @selector(insertObject:atIndex), foo, 2);

[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
    @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__);
    }
    
  • 後署名検索:-(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; }
  • メッセージ転送フローチャート: