runtime使用之消息发送的本质

前言

  • 本章主要是描述如何简单使用runtime,runtime苹果官方是开源的,想要了解更多的朋友可以直接去看官方源码.

一, runtime简介

  • runtime简称为运行时,OC是运行时机制,比如OC的消息机制.
  • 关于C语言,我们都知道它是在编译的时候就会决定去调用哪个函数.
  • 但是,OC是在编译的时候并不能调用函数,而是在运行的时候才会真正的去根据函数名去找到并调用对应的函数的方法.
  • OC与C语言区别之一:OC是运行时机制,C语言是编译时机制.比如说:在OC中,只要你声明了函数,但是没有去实现它,在编译的时候是不会报错的,只有在运行的时候才会报错.但是,C语言只要你没有声明函数,如果直接去实现方法的话,它会在编译的时候就会报错.

二, runtime的作用

1, 发送消息
  • 众所周知, OC是消息机制,其本质就是让对象发送消息,计算机是无法读取OC语言,其本质是将OC语言通过runtime转化为C语言,最后转为二进制.
  • 使用runtime的前提是需要导入#import< objc/message.h>
    或者是#imaport< objc/runtime.h >
  • 只有对象才能发送消息,在runtime中发送消息的方法是:objc_msgSend, runtime中的方法大多都是以objc开头的.

三, runtime的使用场景

  • 使用场景1 : runtime的消息机制,自己写自己的框架
  • 使用场景2 : 如果我们想要去调用别的框架或者是系统中没有暴露出来的方法.
  • 使用场景3 : 如果我们想要研究系统内部有哪些私有方法, 有哪些私有属性.
  • 使用场景4 : 如果我们想要获取到系统自带的控件的子控件
  • 实现原理 : 根据方法名去找对应的方法实现,具体例子如下:
 // 新建一个学生类WGStudent, 在类中什么一个对象方法和类方法.
 #import 

WGStudent.h文件
@interface WGStudent : NSObject

  // - (void)study;
  // + (void)eat;

@end

WGStudent.m文件
#import "WGStudent.h"

@implementation WGStudent

- (void)study {
    NSLog(@"学习数学");
}

+ (void)eat {
    NSLog(@"吃饭");
}
@end
  • 注意 : 这里新建WGStudent类的目的主要是用于解释类的调用原理
#import "ViewController.h"
#import "WGStudent.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

//  对象发送消息
    // OC中调用对象方法
    WGStudent *student = [[WGStudent alloc] init];

    [student study];

    // [student study]的本质就是让对象发送消息
    objc_msgSend(student @selecter(study));

// 类调用对象方法,发送消息
// 调用类方法的方式:两种

    // 第一种通过类名调用
    [student eat];
    // 第二种通过类对象调用
    [[student class] eat];

    // 用类名调用类方法,底层会自动把类名转换成类对象调用
    // 本质:让类对象发送消息
    objc_msgSend([student class], @selector(eat));
}

@end

  • 特别注意 : 如果你这里就运行程序,程序会直接报错,所以这里需要做两步操作.
  • 1, 判断是否导入#import< objc/message.h> 或者 #imaport< objc/runtime.h >
  • 2, 进入工程 -> Build Settting -> msg -> No(不严格检测发送消息的调用)

四, 解析创建一个对象时,如何使用runtime转化OC的.

// 解析创建对象过程
WGStudent *student = [[WGStudent alloc] init];

// 1, 分配存储空间
    WGStudent *student = [WGStudent alloc];
--> 使用runtime创建对象
    objc_msgSend([WGStudent class], @selector(alloc));

// 2, 初始化
    student = [student init];
--> 使用runtime进行初始化
    student = objc_msgSend(student, @selector(init));

// 3, 调用对象方法
    [student study];
--> 使用runtime调用方法
    objc_msgSend(student, @selector(study));

  • 知识拓展 :

  • 1, xcode6开始,苹果不推荐我们使用runtime,把很多函数的参数注释.

  • 2, xcode6做了一些事情,导致不能调用objc_msgSend

  • 注意点:把函数名转换成某个函数指针,一定要用括号包住,在调用


    ((NSObject * (*)(id, SEL))objc_msgSend)(self,@selector(eat));
    objc_msgSend(self,@selector(eat));

你可能感兴趣的