美文网首页
Runtime消息转发

Runtime消息转发

作者: Queen_BJ | 来源:发表于2020-09-14 16:13 被阅读0次
    • 消息转发是在查找IMP失败后执行一系列转发流程。

    ①动态方法解析:

    对象在收到无法解读的消息之后,首先将调用所属类的
    下列类方法:

    +(BOOL)resolveInstanceMethod:(SEL)name
    
    // 举例
    #import <Foundation/Foundation.h>
    @interface Person : NSObject
    - (void)eat; //没有实现
    @end
    
    
    运行结果

    person.m中写入以下代码,对象在接受的无法解读的消息后,首先会调用+(BOOL)resolveInstanceMethod:(SEL)sel或者+ (BOOL)resolveClassMethod:(SEL)sel, 询问是否有动态添加方法来进行处理,处理实例如下

    @implementation Person
    +(BOOL)resolveInstanceM[图片上传中...(截屏2020-09-14 下午3.58.22.png-6c17f1-1600070304990-0)]
    ethod:(SEL)sel
    {
        NSLog(@"sel = %@",NSStringFromSelector(sel));
        return [super resolveInstanceMethod:sel];
    }
    

    具体添加方法如下:

    + (BOOL)resolveInstanceMethod:(SEL)sel {
        if (sel == @selector(eat))
        {
            class_addMethod([self class], sel, (IMP)addeat, "V@");
            return YES;
        }
        return [super resolveInstanceMethod:sel];
    }
    void addeat(id self,SEL sel,NSString *str) 
    {
        NSLog(@"添加成功");
    }
    
    class_addMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp, const char * _Nullable types)
        参数一:被添加方法的类
        参数二:要添加的方法
        参数三:实现这个方法的函数
        参数四:定义返回值和参数类型的字符串(i:代表int  v代表void @:代表参数)
    

    如果动态添加失败,就会进入下面的操作

    ②消息转发重定向

    - (id)forwardingTargetForSelector:(SEL)aSelector
    

    在消息转发机制执行前,Runtime系统会再给我们一次偷梁换柱的机会,即通过重载- (id)forwardingTargetForSelector:(SEL)aSelector方法替换消息的接受者为其他对象。

    新建一个tempObject,定义eat方法,在.m文件中实现
    
    #import "tempObject.h"
    @implementation tempObject
    - (void)eat
    {
        NSLog(@"i am tempObject");
    }
    @end
    

    在person类中将接受消息对象换为tempObject

    -(id)forwardingTargetForSelector:(SEL)aSelector
    {
        return [[tempObject alloc]init];
    }
    

    结果如下:


    ③ 消息转发

    首先获取方法的签名,拿着签名去配发消息,如果不能接受消息就会抛出异常

    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
    - (void)forwardInvocation:(NSInvocation *)anInvocation;
    

    获取方法签名

    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE("")
    {
        //转化字符
        NSString *sel = NSStringFromSelector(aSelector);
        //判断, 手动生成签名
        if([sel isEqualToString:@"eat"])
        {
            return [NSMethodSignature signatureWithObjCTypes:"v@:"];
        }
        else
        {
            return [super methodSignatureForSelector:aSelector];
        }
    }
    

    拿到方法签名配发消息

    - (void)forwardInvocation:(NSInvocation *)anInvocation OBJC_SWIFT_UNAVAILABLE(""){
        NSLog(@"forwardInvocation: %@", NSStringFromSelector([anInvocation selector]));
        //取到消息
        SEL seletor = [anInvocation selector];
        //转发
        tempObject *temp = [[tempObject alloc]init];
        if([temp respondsToSelector:seletor])
        {
            //调用对象,进行转发
            [anInvocation invokeWithTarget:temp];
        }
        else
        {
            return [super forwardInvocation:anInvocation];
        }
    }
    

    如果不能接受消息,抛出异常

    - (void)doesNotRecognizeSelector:(SEL)aSelector
    {
        NSString *selStr = NSStringFromSelector(aSelector);
        NSLog(@"%@不存在",selStr);
    }
    

    相关文章

      网友评论

          本文标题:Runtime消息转发

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