当一个对象调用一个方法,会在底层调用objc_msgSend()方法,如通过isa指针指向类们在方法缓存中查找,如果方法是有序的那么通过二分查找进行,未排序那就一般遍历查询。如果类中找不到会在父类中查找直到元类中;如果这里都没法找到,那就进行消息转发;消息转发我的理解是,尽最大努力让该方法去执行。
001 看是否能接受该SEL
resolveInstanceMethod&&resolveClassMethod
如果可以接受该SEL那么就将该方法转移到在该类中某方法
如果不可以接受那么就找那个target进行执行
002 为该selector找到对应的target来执行
forwardingTargetForSelector返回一个ID类型
003 如果没有target来执行那就需要手动添加方法签名
methodSignatureForSelector&&forwardInvocation
具体代码如下:
//
// TestMessage.m
// LearnMsgForwarding
//
// Created by maochengfang on 2020/10/22.
//
#import "TestMessage.h"
#import "RuntimeTool.h"
#import "BackupTestMessage.h"
@implementation TestMessage
+ (BOOL)resolveClassMethod:(SEL)sel{
if([NSStringFromSelector(sel) isEqualToString:@"testClassFunction"]){
//在元类中添加方法
[RuntimeTool addMethodWithClass:[RuntimeTool getMetaClassWithChildClass:[self class]] withMethodSel:sel withImpMethodSel:@selector(addClassDynamicMethod)];
return YES;
}
return [super resolveClassMethod:sel];
}
+(BOOL)resolveInstanceMethod:(SEL)sel{
if([NSStringFromSelector(sel) isEqualToString:@"testFunction"]){
// //给类对象添加方法
[RuntimeTool addMethodWithClass:[self class] withMethodSel:sel withImpMethodSel:@selector(addDynamicMethod)];
return YES;
}
return [super resolveInstanceMethod:sel];
}
-(id)forwardingTargetForSelector:(SEL)aSelector{
if([NSStringFromSelector(aSelector) isEqualToString:@"testFunction"]){
return [BackupTestMessage new];
}
return [super forwardingTargetForSelector:aSelector];
}
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
if([super methodSignatureForSelector:aSelector] == nil){
NSMethodSignature * sign = [NSMethodSignature signatureWithObjCTypes:"v@:"];
return sign;
}
return [super methodSignatureForSelector:aSelector];
}
-(void)forwardInvocation:(NSInvocation *)anInvocation{
BackupTestMessage *backup= [BackupTestMessage new];
SEL sel = anInvocation.selector;
if([backup respondsToSelector:sel]){
[anInvocation invokeWithTarget:backup];
}else{
[self doesNotRecognizeSelector:sel];
}
}
+ (void)addClassDynamicMethod{
NSLog(@"动态添加类方法");
}
-(void)addDynamicMethod{
NSLog(@"动态添加实例方法");
}
@end
//
// RuntimeTool.m
// LearnMsgForwarding
//
// Created by maochengfang on 2020/10/22.
//
#import "RuntimeTool.h"
#import <objc/runtime.h>
@implementation RuntimeTool
+(Class)getMetaClassWithChildClass:(Class)childClass{
//转换字符串类别
const char * classChar = [NSStringFromClass(childClass) UTF8String];
//需要char的字符串 获取元类
return objc_getMetaClass(classChar);
}
+ (void)addMethodWithClass:(Class)class withMethodSel:(SEL)methodSel withImpMethodSel:(SEL)impMethodSel{
//获取实现的方法内容
Method funtionRealMethod = class_getInstanceMethod(class, impMethodSel);
//实现方法的IMP
IMP methodIMP = method_getImplementation(funtionRealMethod);
//实现方法的类别 返回类型 携带参数 等
const char * types = method_getTypeEncoding(funtionRealMethod);
//对目标添加方法
class_addMethod(class, methodSel, methodIMP, types);
}
@end
//
// BackupTestMessage.m
// LearnMsgForwarding
//
// Created by maochengfang on 2020/10/22.
//
#import "BackupTestMessage.h"
@implementation BackupTestMessage
-(void)testFunction{
NSLog(@"备用类的对象方法testFunction");
}
+(void)testClassFunction{
NSLog(@"备用类的类方法testClassFunction");
}
@end
二、源码分析
resolveClassMethod 会从元类对象执行objc_msgSend,执行本方法
BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
bool resolved = msg(nonmeta, @selector(resolveClassMethod:), sel);
查询是否有实现IMP
IMP imp = lookUpImpOrNil(inst, sel, cls);
/***********************************************************************
* resolveClassMethod
* Call +resolveClassMethod, looking for a method to be added to class cls.
* cls should be a metaclass.
* Does not check if the method already exists.
**********************************************************************/
static void resolveClassMethod(id inst, SEL sel, Class cls)
{
runtimeLock.assertUnlocked();
ASSERT(cls->isRealized());
ASSERT(cls->isMetaClass());
if (!lookUpImpOrNil(inst, @selector(resolveClassMethod:), cls)) {
// Resolver not implemented.
return;
}
Class nonmeta;
{
mutex_locker_t lock(runtimeLock);
nonmeta = getMaybeUnrealizedNonMetaClass(cls, inst);
// +initialize path should have realized nonmeta already
if (!nonmeta->isRealized()) {
_objc_fatal("nonmeta class %s (%p) unexpectedly not realized",
nonmeta->nameForLogging(), nonmeta);
}
}
BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
bool resolved = msg(nonmeta, @selector(resolveClassMethod:), sel);
// Cache the result (good or bad) so the resolver doesn't fire next time.
// +resolveClassMethod adds to self->ISA() a.k.a. cls
IMP imp = lookUpImpOrNil(inst, sel, cls);
if (resolved && PrintResolving) {
if (imp) {
_objc_inform("RESOLVE: method %c[%s %s] "
"dynamically resolved to %p",
cls->isMetaClass() ? '+' : '-',
cls->nameForLogging(), sel_getName(sel), imp);
}
else {
// Method resolver didn't add anything?
_objc_inform("RESOLVE: +[%s resolveClassMethod:%s] returned YES"
", but no new implementation of %c[%s %s] was found",
cls->nameForLogging(), sel_getName(sel),
cls->isMetaClass() ? '+' : '-',
cls->nameForLogging(), sel_getName(sel));
}
}
}
resolveInstanceMethod方法就在类方法中通过objc_msgSend方法执行resolveInstanceMethod
/***********************************************************************
* resolveInstanceMethod
* Call +resolveInstanceMethod, looking for a method to be added to class cls.
* cls may be a metaclass or a non-meta class.
* Does not check if the method already exists.
**********************************************************************/
static void resolveInstanceMethod(id inst, SEL sel, Class cls)
{
runtimeLock.assertUnlocked();
ASSERT(cls->isRealized());
SEL resolve_sel = @selector(resolveInstanceMethod:);
if (!lookUpImpOrNil(cls, resolve_sel, cls->ISA())) {
// Resolver not implemented.
return;
}
BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
bool resolved = msg(cls, resolve_sel, sel);
// Cache the result (good or bad) so the resolver doesn't fire next time.
// +resolveInstanceMethod adds to self a.k.a. cls
IMP imp = lookUpImpOrNil(inst, sel, cls);
if (resolved && PrintResolving) {
if (imp) {
_objc_inform("RESOLVE: method %c[%s %s] "
"dynamically resolved to %p",
cls->isMetaClass() ? '+' : '-',
cls->nameForLogging(), sel_getName(sel), imp);
}
else {
// Method resolver didn't add anything?
_objc_inform("RESOLVE: +[%s resolveInstanceMethod:%s] returned YES"
", but no new implementation of %c[%s %s] was found",
cls->nameForLogging(), sel_getName(sel),
cls->isMetaClass() ? '+' : '-',
cls->nameForLogging(), sel_getName(sel));
}
}
}
检查IMP是否为空对象
static inline IMP
lookUpImpOrNil(id obj, SEL sel, Class cls, int behavior = 0)
{
return lookUpImpOrForward(obj, sel, cls, behavior | LOOKUP_CACHE | LOOKUP_NIL);
}