(十一) [OC高效系列]objc_msgSend的作用

1.为什么说OC是一个动态语言

先上一段代码

void printHello(){
    printf("hello world \n");
}

void printGoodbye(){
    printf("Goodbye,world \n");
}

void doTheThing(int type){
    if(type == 0){
        printHello();
    }else{
        printGoodbye();
    }
}

这段代码中printHelloprintGoodbye两个函数是直接显示在代码中调用的,这就是“静态绑定”,在编译的时候就决定运行时所调用的函数。函数地址直接硬编码到指令之中。

下面再看这段代码

void doTheThing2(int type){
    void (*fnc)();
    if(type == 0 ){
        fnc = printHello;
    }else{
        fnc = printGoodbye;
    }
    fnc();
    
}

这段代码中,编译器在编译期间并不知道最终实际调用的方法,所以并不能将函数地址直接硬编码到指令之中。而是在运行时根据type 的值进行判断来调用相应的函数。这就叫“动态绑定”。

而OC本身语法中的方法调用,是在运行的时候,向该对象发送一个消息,动态调用该对象的一个方法。所以OC是一个动态语言。

2.Objc_msgSend方法

在1中我们说到,OC本身的方法调用是向一个对象发送一个消息,动态调用该对象的额一个方法。
而这个向对象发送消息的API就是Objc_msgSend,原型如下

 id objc_msgSend(id self, SEL op, ...)
  • 第一个参数:接收者
  • 第二个参数:选择子(方法的名字)
  • 后续参数都是消息中的那些参数。

3.Objc_msgSend方法的实际转换

比如下面这一段代码

id returnValue = [someObj messageName:parameter];

在运行时会转换成如下方法,向someObj方法发送消息

id returnValue = objc_msgSend(someObject,@selector(messageName:),parameter);

4.发送消息的传送顺序

  • 在接收者所属类中搜寻方法列表,找到则跳转到实现代码,找不到进行下一步
  • 沿着继承体系向上查找,找到则跳转到实现代码,找不到进行下一步
  • 进行消息派发

消息传送中看似需要上面这么多步骤,但是一旦找到就会缓存到快速映射表里面,每个类都有这样一块缓存,下次再找就非常非常快了。虽然还是没静态绑定的速度快,但是这并不是性能瓶颈所在。

5.一些特别的消息发送函数

  • 如果返回值是结构体
    objc_msgSend_stret
  • 如果返回值是浮点数
    objc_msgSend_fpret
  • 如果是要给超类发消息
    objc_msgSendSuper

6.找到方法实现之后

找到方法实现会跳转到方法实现,OC中每个方法实现都课看做一个简单的c函数:原型如下

 Class_selector(id self ,SEL _cmd,...)

你可能感兴趣的:((十一) [OC高效系列]objc_msgSend的作用)