在开发中离不开方法调用,比如下面最简单的调用
Person *p = [[Person alloc] init];
[p nxyTest:10]; 这句代码的底层实现是 objc_msgSend(p, @selector(test:));
方法调用的本质就是发消息 下面就来看看 objc_msgSend 是如何一步步实现的
-
消息发送
如上面流程图所示, 依次去方法缓存(cache), 方法列表(class_rw_t),父类对应的缓存和方法列表去找, 如果有就去调用,如果没有找到,就执行下一个阶段"动态方法解析"
-
动态方法解析

@interface Person : NSObject
-(void)test;
+(void)replaceClassTest;
@end
@implementation Person
//动态添加对象方法
+(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));
//返回YES表示有动态添加方法
return YES;
}
return [super resolveInstanceMethod:sel];
}
-(void)other
{
NSLog(@"%s",__func__);
}
@end
//动态添加类方法
+(BOOL)resolveClassMethod:(SEL)sel{
if (sel == @selector(classTest)) {
Method method = class_getClassMethod(self, @selector(replaceClassTest));
//动态添加方法的实现
class_addMethod(object_getClass(self), sel, method_getImplementation(method), method_getTypeEncoding(method));
return YES;
}
return [super respondsToSelector:sel];
}
+(void)replaceClassTest{
NSLog(@"++++++++++++++replaceClassTest");
}
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Person *p = [[Person alloc] init];
[p test];
[Person replaceClassTest];
}
@end
Person类中只有test/replaceClassTest方法的声明,而没有实现,在外部调用test/replaceClassTest方法的时候,在第一阶段消息发送没有找到对应的方法去调用,所以来到了第二阶段动态解析,可以在这里动态的添加方法
3.消息转发

//对象方法
@implementation Person
//消息转发
-(id)forwardingTargetForSelector:(SEL)aSelector
{
if (aSelector == @selector(test)) {
/*如果这里返回了一个sutdent对象,
那么就会调用objc_msgSend(student, aSelector),
如果这里返回nil,则会调用methodSignatureForSelector*/
return [[Student alloc] init];
}
return [super forwardingTargetForSelector:aSelector];
}
//如果返回了NSMethodSignature对象, 接下来会调用forwardInvocation方法, 如果返回nil,报方法找不到的错误
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
if (aSelector == @selector(test:)) {
return [NSMethodSignature signatureWithObjCTypes:"v@"];
// return [[[Student alloc] init] methodSignatureForSelector:aSelector];
// Method method = class_getInstanceMethod([Student class], aSelector);
// return [NSMethodSignature signatureWithObjCTypes:method_getTypeEncoding(method)];
}
return [super methodSignatureForSelector:aSelector];
}
/**
NSInvocation 是封装了一个方法调用, 包括 : 方法调用者 方法名 方法参数
anInvocation.target 方法调用者
anInvocation.selector 方法名
anInvocation getArgument:<#(nonnull void *)#> atIndex:<#(NSInteger)#> 方法参数
*/
-(void)forwardInvocation:(NSInvocation *)anInvocation
{
//获取方法的参数
int argument;
// [anInvocation getArgument:&argument atIndex:2];
// NSLog(@"%d",argument);
[anInvocation invokeWithTarget:[[Teacher alloc]init]];
}
@end
//类方法
+(id)forwardingTargetForSelector:(SEL)aSelector {
if (aSelector == @selector(classTest)) {
return [Student class];
}
return [super forwardingTargetForSelector:aSelector];
}
+(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if (aSelector == @selector(classTest)) {
Method method = class_getInstanceMethod(object_getClass([Student class]), aSelector);
return [NSMethodSignature signatureWithObjCTypes:method_getTypeEncoding(method)];
}
return [super methodSignatureForSelector:aSelector];
}
+(void)forwardInvocation:(NSInvocation *)anInvocation {
[anInvocation invokeWithTarget:[Student class]];
}