zoukankan      html  css  js  c++  java
  • iOS Runtime的消息转发机制

    前面我们已经讲解Runtime的基本概念和基本使用,如果大家对Runtime机制不是很了解,可以先看一下以前的博客,会对理解这篇博客有所帮助!!!

    Runtime基本概念:https://www.cnblogs.com/guohai-stronger/p/9154889.html

    Runtime基本使用:https://www.cnblogs.com/guohai-stronger/p/9184356.html

    看过上面两篇博客之后,大家可能会对Runtime有所了解,但在上述讲述Runtime还有一个问题,当对象无法接收到相关的消息时候,又会发生什么?这就是我们即将讲的消息转发机制

    一、前言

    在讲述消息转发机制前,先通过一个简单的例子

    id num = @123;
    //输出123
    NSLog(@"%@", num);
    //程序崩溃,报错[__NSCFNumber appendString:]: unrecognized selector sent to instance 0x7b27
    [num appendString:@"Hello World"];

    在程序代码中加入上面代码,运行过程为:先在相关的类中,搜索方法列表,如果出现找不到则会一直向上搜索到根部(也就是NSObject);如果出现还找不到并且消息转发都失败,此时就会执行doesNotRecognizeSelector:紧接着方法报unrecognized selector错误?

    下面我们来讲述消息转发的过程中,为什么经常出现消息的最后三次机会?

    第一步:所属类的动态方法解析

    首先,如果沿着继承树没有搜索到相关的方法时,则就会向接受者所属的类进行一次请求,看是否可以动态的添加一个方法,如下:

    +(BOOL)resolveInstanceMethod:(SEL)name

    注意这是一个类方法,因为向接受者所属的类进行一次请求。

    下面我们举个例子:

    #import "ViewController.h"
    #import <objc/runtime.h>
    
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.title = @"Runtime";
        [self performSelector:@selector(dynamicSelector) withObject:nil];
    }
    
    + (BOOL)resolveInstanceMethod:(SEL)sel{
        if (sel == @selector(dynamicSelector)) {
            class_addMethod([self class],sel, (IMP)myMehtod,"v@:");
            return YES;
        }else{
            return [super resolveInstanceMethod:sel];
        }
             
    }
    
    void myMehtod(id self,SEL _cmd){
        NSLog(@"This is added dynamic");
    }

    在看结果之前,我们先简单了解下:class_addMethod(上面出现的)

    BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)

    此函数共有四个参数:

    • Class cls:要添加的类对象
    • name:添加后的selector方法名字
    • imp:实现方法
    • type:方法参数的编码

    方法的返回值为BOOL类型:YES表示本类可以处理;NO代表需要使用转发机制

    下面是上面的运行结果,结果如下:

    如果第一步不能处理,会进行到第二步。

    第二步:调用forwardingTargetForSelector把任务转发给另一个对象。

    #import "ViewController.h"
    #import <objc/runtime.h>
    
    @interface CustomObject : NSObject
    -(void)dynamicSelector;
    @end
    @implementation CustomObject
    
    -(void)dynamicSelector{
        NSLog(@"hello world");
    }
    @end



    @interface ViewController () @property (strong,nonatomic)CustomObject * myObj; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.myObj = [[CustomObject alloc] init]; [self performSelector:@selector(dynamicSelector) withObject:nil]; } -(id)forwardingTargetForSelector:(SEL)aSelector{ if (aSelector == @selector(dynamicSelector) && [self.myObj respondsToSelector:@selector(dynamicSelector)]) { return self.myObj; }else{ return [super forwardingTargetForSelector:aSelector]; } } @end

    如果第二步骤也不能处理的时候,会交给第三步骤。

    第三步:调用forwardInvocation转发给其他

    #import "ViewController.h"
    #import <objc/runtime.h>
    
    @interface CustomObject : NSObject
    -(void)dynamicSelector;
    @end
    @implementation CustomObject
    
    -(void)dynamicSelector{
        NSLog(@"hello world");
    }
    @end
    @interface ViewController ()
    @property (strong,nonatomic)CustomObject * myObj;
    @end
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.myObj = [[CustomObject alloc] init];
        [self performSelector:@selector(dynamicSelector) withObject:nil];
    
    }
    -(void)forwardInvocation:(NSInvocation *)anInvocation{
        if ([self.myObj respondsToSelector:[anInvocation selector]]) {
            [anInvocation invokeWithTarget:self.myObj];
        }else{
            [super forwardInvocation:anInvocation];
        }
    }
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
        return [CustomObject instanceMethodSignatureForSelector:aSelector];
    }
    @end

    上面就是iOS Runtime消息的转发机制,欢迎指正!!!

  • 相关阅读:
    Chrome扩展开发之一——Chrome扩展的文件结构
    Chrome扩展开发(Gmail附件管理助手)系列之〇——概述
    Springfox与swagger的整合使用
    Maven的简单使用
    关于接口功能自动化的思考
    发版流程优化备忘录
    Aho-Corasick 自动机 学习笔记
    Luogu P1495 曹冲养猪
    Luogu P2670 【扫雷游戏】
    1.1 整除
  • 原文地址:https://www.cnblogs.com/guohai-stronger/p/9408545.html
Copyright © 2011-2022 走看看