美文网首页
Runtime:objc_msgSend 消息发送

Runtime:objc_msgSend 消息发送

作者: 东方诗空 | 来源:发表于2022-03-29 11:19 被阅读0次

objc_msgSend

OC中的方法调用,其实都是转换为objc_msgSend函数的调用

  • objc_msgSend的执行流程可以分为3大阶段
    1、消息发送
    2、动态方法解析
    3、消息转发

objc_msgSend消息发送

image.png

objc_msgSend 动态方法解析

image.png
- (void)other
{
   NSLog(@"%s", __func__);
}

+ (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 c_other(id self, SEL _cmd)
{
    NSLog(@"c_other - %@ - %@", self, NSStringFromSelector(_cmd));
}
// 类方法的动态解析
+ (BOOL)resolveClassMethod:(SEL)sel
{
    if (sel == @selector(test)) {
        // 第一个参数是object_getClass(self)
        class_addMethod(object_getClass(self), sel, (IMP)c_other, "v16@0:8");
        return YES;
    }
    return [super resolveClassMethod:sel];
}

+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    if (sel == @selector(test)) {
        // 动态添加test方法的实现
        class_addMethod(self, sel, (IMP)c_other, "v16@0:8");

        // 返回YES代表有动态添加方法
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}

objc_msgSend消息转发

image.png
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    class_addMethod(<#Class  _Nullable __unsafe_unretained cls#>, <#SEL  _Nonnull name#>, <#IMP  _Nonnull imp#>, <#const char * _Nullable types#>)
}

- (id)forwardingTargetForSelector:(SEL)aSelector
{
    if (aSelector == @selector(test)) {
        // objc_msgSend([[MJCat alloc] init], aSelector)
        return [[MJCat alloc] init];
    }
    return [super forwardingTargetForSelector:aSelector];
}

// 方法签名:返回值类型、参数类型
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    if (aSelector == @selector(test)) {
        return [NSMethodSignature signatureWithObjCTypes:"v16@0:8"];
    }
    return [super methodSignatureForSelector:aSelector];
}

// NSInvocation封装了一个方法调用,包括:方法调用者、方法名、方法参数
//    anInvocation.target 方法调用者
//    anInvocation.selector 方法名
//    [anInvocation getArgument:NULL atIndex:0]
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
//    anInvocation.target = [[MJCat alloc] init];
//    [anInvocation invoke];

    [anInvocation invokeWithTarget:[[MJCat alloc] init]];
}

可以在下面代码中尽情的变换

对象方法消息转发


- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    if (aSelector == @selector(test:)) {
//        return [NSMethodSignature signatureWithObjCTypes:"v20@0:8i16"];
        return [NSMethodSignature signatureWithObjCTypes:"i@:i"];
//        return [[[MJCat alloc] init] methodSignatureForSelector:aSelector];
    }
    return [super methodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    // 参数顺序:receiver、selector、other arguments
//    int age;
//    [anInvocation getArgument:&age atIndex:2];
//    NSLog(@"%d", age + 10);
    
    
    // anInvocation.target == [[MJCat alloc] init]
    // anInvocation.selector == test:
    // anInvocation的参数:15
    // [[[MJCat alloc] init] test:15]
    
    [anInvocation invokeWithTarget:[[MJCat alloc] init]];
    
    int ret;
    [anInvocation getReturnValue:&ret];
    
    NSLog(@"%d", ret);
}

类方法消息转发

+ (id)forwardingTargetForSelector:(SEL)aSelector
{
   // objc_msgSend([[MJCat alloc] init], @selector(test))
   // [[[MJCat alloc] init] test]
   if (aSelector == @selector(test)) return [[MJCat alloc] init];

   return [super forwardingTargetForSelector:aSelector];
}

+ (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
   if (aSelector == @selector(test)) return [NSMethodSignature signatureWithObjCTypes:"v@:"];
   
   return [super methodSignatureForSelector:aSelector];
}

+ (void)forwardInvocation:(NSInvocation *)anInvocation
{
   NSLog(@"1123");
}

@dynamic是告诉编译器不用自动生成getter和setter的实现,等到运行时再添加方法实现

应用:
通过动态解析可以做一些方法拦截

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    // 本来能调用的方法
    if ([self respondsToSelector:aSelector]) {
        return [super methodSignatureForSelector:aSelector];
    }
    
    // 找不到的方法
    return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}

// 找不到的方法,都会来到这里
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    NSLog(@"找不到%@方法", NSStringFromSelector(anInvocation.selector));
}

相关文章

网友评论

      本文标题:Runtime:objc_msgSend 消息发送

      本文链接:https://www.haomeiwen.com/subject/ukafjrtx.html