文章目录
一、instrumentObjcMessageSends 系统日志探索
1. 它是什么?
instrumentObjcMessageSends是系统的日志,是苹果的私有API,我们可以控制log开关,打印日志信息。
2. 它的由来?
//在查看 IMP
//1.lookUpImpOrForward(id inst, SEL sel, Class cls, int behavior) 方法的时候。 在查找到IMP, done 后续,
//2. 调用了 log_and_fill_cache(cls, imp, sel, inst, curClass);
// 源码如下
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
cls->cache.insert(sel, imp, receiver);
}
// 3. 发现了 objcMsgLogEnabled 这个字段,,全局搜索下这个字段。 发现它默认是false,就只有在一个地方进行了设置
//4. 设置的方法为 void instrumentObjcMessageSends(BOOL flag) ,所以我们可以在源码中,先申明这个方法,然后在调用,系统会帮我们找到他的实现。
3. 日志位置
快捷键: command + shift + g
文件位置为: /tmp/msgSend-***
4. 代码使用
//1. 定义下,不然会报找不到这个api错误
extern void instrumentObjcMessageSends(BOOL flag);
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 2. 打开记录日志操作
instrumentObjcMessageSends(true);
Person *person = [Person alloc];
[person sayHello];
// 3. 关闭日志操作
instrumentObjcMessageSends(false);
NSLog(@"Hello, World!");
}
return 0;
}
二、消息转发流程
imp查询流程总结
为了查找到 imp, 总结下一共经过的流程,防止思路跟不上。
0. 寻找 sel对应的 imp
1. objc_msgSend cache 快速查找
2. 慢速方法查找 methlist
3. 动态方法决议 resolveInstanceMethod
4. 消息快速转发(让别人做 ,一般可以定义一个专门的对象,进行消息处理) forwardingTargetForSelector
5. 消息慢速转发 , (比快速转发更加灵活) methodSignatureForSelector 和 forwardInvocation 配对出现。
1.动态方法决议后续转发流程
上面通过系统的日志,故意让方法找不到,让系统崩溃,然后打开日志看到整个的方法转发过程,里面有好几个方法。
+ LGPerson NSObject resolveInstanceMethod:
+ LGPerson NSObject resolveInstanceMethod:
- LGPerson NSObject forwardingTargetForSelector:
- LGPerson NSObject forwardingTargetForSelector:
- LGPerson NSObject methodSignatureForSelector:
- LGPerson NSObject methodSignatureForSelector:
+ LGPerson NSObject resolveInstanceMethod:
+ LGPerson NSObject resolveInstanceMethod:
- LGPerson NSObject doesNotRecognizeSelector:
- LGPerson NSObject doesNotRecognizeSelector:
第一个方法resolveInstanceMethod这个是我们上篇博客介绍的,方法的动态决议。
重点看后面的方法。
2. forwardingTargetForSelector 快速转发流程
// 对象方法快速转发
-(id)forwardingTargetForSelector:(SEL)aSelector {
NSLog(@"%@ : %s",self,__func__);
// 背锅侠 - 专业处理没有响应的方法
// 方式二: 指定对象,去添加方法并实现。
// IMP myImp = class_getMethodImplementation([LGTeacher class], aSelector);
// Method method = class_getInstanceMethod([LGTeacher class], aSelector);
//
// const char *type = method_getTypeEncoding(method);
//
// bool isSuccess = class_addMethod([LGTeacher class], aSelector, myImp, type);
// 方式一: 知道这个对象里面实现了方法
return [LGTeacher alloc];
}
3. methodSignatureForSelector慢速转发流程
// 对象方法的慢速转发 相比于快速转发更加灵活,可以选择处理或者不处理。
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
NSLog(@"%@ : %s",self,__func__);
if (aSelector == @selector(say666)) {
// 拦截这个方法。 这里没有实现,只是保存这个事务,
Method method = class_getInstanceMethod([LGTeacher class], aSelector);
const char *type = method_getTypeEncoding(method);
return [NSMethodSignature signatureWithObjCTypes:type];
}
return [super methodSignatureForSelector:aSelector];
}
// 和methodSignatureForSelector 成对出现。不然拦截不到错误。
- (void)forwardInvocation:(NSInvocation *)anInvocation {
SEL selector = anInvocation.selector ;
LGTeacher *teacher = [[LGTeacher alloc] init];
if ( [self respondsToSelector

本文详细探讨了iOS开发中的消息转发机制,包括instrumentObjcMessageSends的日志探索,动态方法决议,快速与慢速转发流程,以及resolveInstanceMethod为何调用两次的分析。通过对CoreFoundation的反编译,揭示了底层转发机制的关键步骤,帮助开发者更好地理解和处理Objective-C的消息转发问题。
最低0.47元/天 解锁文章
3万+

被折叠的 条评论
为什么被折叠?



