如果对象没有实现这个方法,父类也没有实现这个方法,那么就会进入动态解析阶段
objc_msgSend()消息发送的三大阶段,第二阶段就是动态方法解析
调用Person对象的test方法
Person *p = [[Person alloc] init];
[p test];
typedef struct objc_method *Method;
首先证明struct objc_method == method_t
- (void)other{
NSLog(@"%s",__func__);
}
struct method_t{
SEL sel;
char *types;
IMP imp;
};
+ (BOOL)resolveInstanceMethod:(SEL)sel{
if (sel == @selector(test)) {
// 获取其他方法 第一个参数:类对象
// Method method = class_getInstanceMethod(self, @selector(other));
struct method_t *other = (struct method_t *)class_getInstanceMethod(self, @selector(other));
// other v16@0:8 0x10c7152a0
NSLog(@"%s %s %p",other->sel,other->types,other->imp);
// 给self这个类对象 sel方法名,添加实现other->imp
class_addMethod(self, sel, other->imp, other->types);
// YES可以省略,按照规范最好写上
return YES;
}
return [super resolveInstanceMethod:sel];
}
打印IMP实现,证明这个IMP就是other
方法
p (IMP)0x10c7152a0
(IMP) $0 = 0x000000010c7152a0 (test`-[Person other] at Person.m:16)
使用原生添加方法
+ (BOOL)resolveInstanceMethod:(SEL)sel{
if (sel == @selector(test)) {
// 获取其他方法
Method method = class_getInstanceMethod(self, @selector(other));
// 动态为test添加方法的实现
class_addMethod(self, sel, method_getImplementation(method), method_getTypeEncoding(method));
return YES;
}
return [super resolveInstanceMethod:sel];
}
使用C语言函数,动态的添加方法的实现
void c_language_method(id self, SEL _cmd){
// <Person: 0x600003154e20> test
NSLog(@"%@ %@",self,NSStringFromSelector(_cmd));
}
+ (BOOL)resolveInstanceMethod:(SEL)sel{
if (sel == @selector(test)) {
// c语言函数名,就是函数地址 IMP就是函数地址
class_addMethod(self, sel, (IMP)c_language_method, "v16@0:8");
}
return [super resolveInstanceMethod:sel];
}
c语言函数名,就是函数地址 IMP就是函数地址
方法中,types
源码的解析(返回值类型.参数类型)
// "i24@0:8i16f20"
// i 表示 int
// 24所以参数所占用的字节 8 + 8 + 4 + 4
// @ 参数是id类型
// 0表示第一个参数@从第0个字节开始算
// :表示参数是SEL类型
// 8表示第二个参数从第8个字节开始算
// i表示 int类型参数
// 16第三个参数从第16个字节开始算
// f表示 float类型参数
// 20第四个参数从第20个字节开始算
- (int)test:(int)age height:(float)height;
动态添加类方法
从元类对象的缓存方法列表去找,再从元类对象的方法列表去找,再去父类的元类对象中找
void c_language_method(id self, SEL _cmd){
// 消息接受者是这个类 Person
// Person test
NSLog(@"%@ %@",self,NSStringFromSelector(_cmd));
}
+ (BOOL)resolveClassMethod:(SEL)sel{
if (sel == @selector(test)) {
// 这里不是self,而是元类对象,通过类对象获取元类对象
class_addMethod(object_getClass(self), sel, (IMP)c_language_method, "v16@0:8");
return YES;
}
return [super resolveClassMethod:sel];
}