美文网首页
Objc_msgSend流程(三)之消息转发

Objc_msgSend流程(三)之消息转发

作者: _涼城 | 来源:发表于2020-10-03 08:55 被阅读0次
    消息转发

    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

    相关文章

      网友评论

          本文标题:Objc_msgSend流程(三)之消息转发

          本文链接:https://www.haomeiwen.com/subject/lxxwuktx.html