消息转发
在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; } } //... }
发现objcMsgLogEnabled
为true
的情况,可以调用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
前缀的文件,打开查看
因此,在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:
网友评论