Objc_msgSend流程(三)之消息转发

消息转发

Objc_msgSend流程(二)之方法慢速查找lookUpImpOrForward中,会调用log_and_fill_cache,其中会调用logMessageSend函数

  • log_and_fill_cache

    static void
    log_and_fill_cache(Class cls, IMP imp, SEL sel, id receiver, Class implementer)
    {
    #if SUPPORT_MESSAGE_LOGGING
        if (slowpath(objcMsgLogEnabled && implementer)) {
            bool cacheIt = logMessageSend(implementer->isMetaClass(), 
                                          cls->nameForLogging(),
                                          implementer->nameForLogging(), 
                                          sel);
            if (!cacheIt) return;
        }
    #endif
        cache_fill(cls, sel, imp, receiver);
    }
    
  • logMessageSend

    bool logMessageSend(bool isClassMethod,
                        const char *objectsClass,
                        const char *implementingClass,
                        SEL selector)
    {
        char    buf[ 1024 ];
    
        // Create/open the log file
        if (objcMsgLogFD == (-1))
        {
            snprintf (buf, sizeof(buf), "/tmp/msgSends-%d", (int) getpid ());
            objcMsgLogFD = secure_open (buf, O_WRONLY | O_CREAT, geteuid());
            if (objcMsgLogFD < 0) {
                // no log file - disable logging
                objcMsgLogEnabled = false;
                objcMsgLogFD = -1;
                return true;
            }
        }
        //...
    }
    

发现objcMsgLogEnabledtrue的情况,可以调用logMessageSend,并输出在tmp路径下,搜索objcMsgLogEnabled,找到instrumentObjcMessageSends函数

  • instrumentObjcMessageSends

    void instrumentObjcMessageSends(BOOL flag)
    {
        bool enable = flag;
    
        // Shortcut NOP
        if (objcMsgLogEnabled == enable)
            return;
    
        // If enabling, flush all method caches so we get some traces
        if (enable)
            _objc_flush_caches(Nil);
    
        // Sync our log file
        if (objcMsgLogFD != -1)
            fsync (objcMsgLogFD);
    
        objcMsgLogEnabled = enable;
    }
    

要想打印方法日志,需要声明extern void instrumentObjcMessageSends(BOOL flag);,并在执行方法前开启,执行方法后关闭;

instrumentObjcMessageSends(true);
[person say1];
instrumentObjcMessageSends(false);

/tmp/路径下找到msgSends前缀的文件,打开查看

msgSends.png

  因此,在objc_msgSend中,如果查找流程未找到方法实现,并且未实现动态方法决议,就会调用

  • 快速转发

    forwardingTargetForSelector

    可以在类中重新该方法forwardingTargetForSelector,返回一个接收类,实现消息转发

    - (id)forwardingTargetForSelector:(SEL)aSelector{
    
        return [super forwardingTargetForSelector:aSelector];
    }
    
  • 慢速转发

    methodSignatureForSelector ,需要搭配forwardInvocation:使用,实现之后就不会再执行``doesNotRecognizeSelector:`

    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
    }
    
    - (void)forwardInvocation:(NSInvocation *)anInvocation{
    
    }
    

    resolveInstanceMethod

  • 最终仍未找到,调用

    doesNotRecognizeSelector:

消息转发机制流程
消息转发流程.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容