objc_msgSend执行流程
objc_msgSend执行流程
OC中方法调用,其实都是转换成objc_msgSend函数调用
objc_msgSend的执行流程可以分为3个阶段
- 消息发送
- 动态方法解析
- 消息转发
1.消息发送
上图就是消息发送阶段的过程,如果查找到最顶级的类,仍然没有找到相应的方法,则会进入下一个阶段
2. 动态方法解析
我们在这一步中动态添加的方法,是添加到当前类/当前元类 的class_rw_t表中,调用之后,方法会缓存在cache表中 (cache表底层是通过散列表实现的,效率高,这里散列表的大概实现原理是通过key值&MASK得到一个序号(这个序号可能是相同,可能不是放在首位),这样通过序号可以直接找到当前存储的对象,通过key拿到value)
// 动态添加实例方法,添加的方法存在对象的方法列表中
+ resolveInstanceMethod:
- 在程序运行阶段动态添加一个实例方法
struct method_t {
SEL sel;
char *types;
IMP imp;
};
- (void)testABC {
NSLog(@"%s",__func__);
}
+ (BOOL)resolveInstanceMethod:(SEL)sel {
if (sel == @selector(test)) {
struct method_t *method = (struct method_t *)class_getInstanceMethod(self, @selector(testABC));
class_addMethod(self, sel, method->imp, method->types);
return YES;
}
return [super resolveInstanceMethod:sel];
}
还可以这么写
- (void)testABC {
NSLog(@"%s",__func__);
}
+ (BOOL)resolveInstanceMethod:(SEL)sel {
if (sel == @selector(test)) {
Method method = class_getInstanceMethod(self, @selector(testABC));
class_addMethod(self, sel, method_getImplementation(method), method_getTypeEncoding(method));
return YES;
}
return [super resolveInstanceMethod:sel];
}
- 在程序运行阶段动态添加一个类方法
+ (BOOL)resolveClassMethod:(SEL)sel {
if (sel == @selector(test)) {
Method method = class_getInstanceMethod(self, @selector(other));
// 这里是往元类中添加方法,所以需要通过object_getClass获取元类
class_addMethod(object_getClass(self), sel, method_getImplementation(method), method_getTypeEncoding(method));
return YES;
}
return [super resolveClassMethod:sel];
}
3. 消息转发
消息转发
- (id)forwardingTargetForSelector:(SEL)aSelector
{
if (aSelector == @selector(test)) {
// 交给student类处理
return [[MJStudent alloc] init];
}
// 如果这里不处理的话,走方法 methodSignatureForSelector:
return [super forwardingTargetForSelector:aSelector];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
if (aSelector == @selector(test)) {
// 如果这里处理了,会走方法 forwardInvocation:
// [email protected]:8 是方法签名
return [NSMethodSignature signatureWithObjCTypes:"[email protected]:8"];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
// 这里可以随意处理
}