美文网首页
动态方法解析和消息转发的使用

动态方法解析和消息转发的使用

作者: 陈_振 | 来源:发表于2018-05-30 09:35 被阅读0次

如果给一个对象发送消息,而该对象并没有实现该方法,则程序在崩溃之前会有两次挽回的机会:

  1. 动态方法解析
    --A.如果发送的消息是实例方法(-)


    Screen Shot 2018-05-30 at 08.36.21.png

如果是OC方法,使用上图上面框中的方式;
如果是C类型的方法,使用下面框中的方式。

-- B.如果发送的消息是类方法(+)
与上面的实现只有两点区别,
第一,调用的是resolveClassMethod:方法;
第二就是在使用class_addMethod()方法是,第一个参数不能是self,因为self表示类对象,而类方法应该添加到元类对象中,因此第一个参数应该为:objc_getClass(self)

void other(id self, SEL _cmd) {
    
}

+ (BOOL)resolveClassMethod:(SEL)sel {
    if (sel == @selector(test)) {
        class_addMethod(object_getClass(self),
                        sel,
                        (IMP)other,
                        "v16@0:8");
        return YES;
    }
    
    return [super resolveClassMethod:sel];
}
  1. 消息转发

--A.转发实例方法

Screen Shot 2018-05-30 at 10.52.36.png
- (id)forwardingTargetForSelector:(SEL)aSelector
{
    if (aSelector == @selector(test)) {
        // objc_msgSend([[MJCat alloc] init], aSelector)
        return [[MJCat alloc] init];
    }
    return [super forwardingTargetForSelector:aSelector];
}

如果上面的方法返回nil则执行下面的方法:

// 方法签名:返回值类型、参数类型
- (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];
// 获取传入的参数
    int a;
    [anInvocation getArgument:&a atIndex:2];  // index从2开始,前两个存储的是默认的隐含参数(self 和 _cmd)
    [anInvocation invokeWithTarget:[[MJCat alloc] init]];

   // 消息转发后,用来获取方法的返回值
    int returnValue;
    [anInvocation getReturnValue:&returnValue];

}

--B.转发类方法

注意:方法开头的"+"以及返回的是类对象

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

如果上面的方法返回nil则执行下面的方法:

// 方法签名:返回值类型、参数类型
+ (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];
// 获取传入的参数
    int a;
    [anInvocation getArgument:&a atIndex:2];  // index从2开始,前两个存储的是默认的隐含参数(self 和 _cmd)
    [anInvocation invokeWithTarget:[MJCat class];

   // 消息转发后,用来获取方法的返回值
    int returnValue;
    [anInvocation getReturnValue:&returnValue];

}

利用消息转发降低因unrecognized selector sent to instance导致的崩溃率,收集unrecognized selector sent to instance的错误信息

在NSObject的Category中重写这两个方法,那么当有不能识别的方法被发送给接收者时,不会导致崩溃,同时可以收集错误信息。

#import "NSObject+Unrecognized.h"

@implementation NSObject (Unrecognized)

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {

    return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    NSLog(@"找不到%@方法", NSStringFromSelector(anInvocation.selector));
}

+ (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    
    return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}

+ (void)forwardInvocation:(NSInvocation *)anInvocation {
    NSLog(@"找不到%@方法", NSStringFromSelector(anInvocation.selector));
}

@end
``

相关文章

  • Runtime(二)

    objc_msgSend 包括以下三个步骤 消息发送 动态方法解析 消息转发 消息发送 动态方法解析 消息转发 如...

  • unrecognized selector sent to in

    消息转发以及动态解析方法 消息转发机制基本上分为三个步骤: 动态方法解析 备用接收者 完整转发 首先,对于动态方法...

  • MG--iOS 消息机制

    msgSend 消息发送 动态方法解析 动态添加方法image.png 消息转发

  • Runtime

    定义 runtime 详解文章 1. 消息转发 动态方法解析(方法调用的必经之路) 快速转发(动态解析失败后,指...

  • 动态方法解析和消息转发的使用

    如果给一个对象发送消息,而该对象并没有实现该方法,则程序在崩溃之前会有两次挽回的机会: 动态方法解析--A.如果发...

  • Runtime 方法调用本质(消息发送、动态方法解析、消息转发)

    动态方法解析、消息转发 如果方法实现(imp)没有找到会尝试一次动态方法解析,源码如 动态方法解析调用 "_cla...

  • iOS面试题总结2018年3月

    一、Runtime的消息转发机制1.动态方法解析 备用接受者3.完整转发 1.动态方法解析对象在接受到未知消息时,...

  • 消息转发流程

    动态方法解析 备用接收者 完整消息转发

  • iOS-浅谈OC中的消息机制

    目录 简介消息发送objc_msgSend动态方法解析消息转发---- 转发接收者---- 转发调用补充---- ...

  • iOS 消息转发机制

    消息转发机制分为三步: 一、动态方法解析 二、快速消息转发 三、标准消息转发(normal forwarding)...

网友评论

      本文标题:动态方法解析和消息转发的使用

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