iOS objc_msgSend笔记

2021-11-07  本文已影响0人  山杨

三大阶段:1. 消息发送 2. 动态方法解析 3. 消息转发

消息发送
动态方法解析
void c_errorMethod(id self, SEL _cmd)
{
   NSLog(@"%s", __func__);
}
- (void)errorMethod {
   NSLog(@"%s", __func__);
}

// 动态方法解析 - 实例对象方法
+ (BOOL)resolveInstanceMethod:(SEL)sel {

   if (sel == @selector(method)) {
       
       Method errorMethod = class_getInstanceMethod(self, @selector(errorMethod));
       IMP errorImp = method_getImplementation(errorMethod);
       const char *type = method_getTypeEncoding(errorMethod);
       class_addMethod(self, sel, errorImp, type);
       return YES;
   }
   return [super resolveInstanceMethod:sel];
}

// 动态方法解析 - 类方法
+ (BOOL)resolveClassMethod:(SEL)sel {

   if (sel == @selector(method)) {
       // 获取元类对象
       Class metaClass = object_getClass(self);
       // c_errorMethod的编码为"v@:"
       // 规则:v表示返回值void,@表示第1个参数是对象类型,:表示第2个参数是SEL类型
       // 完整规则参考TypeEncoding官方文档
       const char *type = "v@:";
       class_addMethod(metaClass, sel, (IMP)c_errorMethod, type);
       return YES;
   }
   return [super resolveClassMethod:sel];
}

TypeEncoding官方文档

如果已经进行过动态方法解析,依然没有处理该消息,则会进入消息转发阶段

消息转发
- (id)forwardingTargetForSelector:(SEL)aSelector {
    
    if (aSelector == @selector(method)) {
        // 如果返回了一个新的对象,则会触发objc_msgSend(aNewObj, aSelector)
        return aNewObj;
    }
    return [super forwardingTargetForSelector:aSelector];
}
// 如果forwardingTargetForSelector:没有返回一个合适的对象
// 那么就会触发methodSignatureForSelector:方法
// 返回一个NSInvocation对象给forwardInvocation:.
// 通过子类重写该方法,将消息转发给其他对象
// NSInvocation对象使用来自methodSignatureForSelector:返回的信息创建
/*
anInvocation.target;//消息接收对象
anInvocation.selector;//方法名
[anInvocation getReturnValue:];//返回值
[anInvocation getArgument: atIndex:];// 参数
*/
- (void)forwardInvocation:(NSInvocation *)anInvocation {
    
}
// 如果返回值为nil,则不会触发forwardInvocation:
// 而会去直接触发doesNotRecognizeSelector:抛出异常
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    
    if (aSelector == @selector(method)) {

        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
    }
    return [super methodSignatureForSelector:aSelector];
}

//备注: doesNotRecognizeSelector:方法可以重写,但不能正常返回
//(换句话说就是在结束时必须引发NSInvalidArgumentException异常)

值得注意的是系统提供的-forwardingTargetForSelector:方法是针对某个实例对象调用对象方法的,如果要调用类对象的类方法需要用
+forwardingTargetForSelector:方法。
同样forwardInvocationmethodSignatureForSelector也遵循这样的方式修改为针对类对象方法的调用。

上一篇下一篇

猜你喜欢

热点阅读