iOS底层原理探索-06- Runtime之方法的本质

409 阅读2分钟

《目录-iOS & OpenGL & OpenGL ES & Metal》
对象和类之前已经分析过了,今天来分析一下方法,说到方法就不得不探究一下Runtime了~

一、Runtime

1、Runtime的定义

Runtime是一套API。

详细来说,是一套由c、c++、汇编一起编写而成,并为oc代码提供运行时功能的api。

为什么要这么费劲巴拉的搞这么一套东西,不直接用oc呢?

  • 因为oc对于计算机来说是一门高级语言,而c、c++、汇编相比oc,更加稳定,执行效率也更快。总体来说是为了稳定性和高效率!

运行时 & 编译时

  • 运行时:代码跑起来的时间,代码会被装载在内存

  • 编译时:正在编译的时间,将源代码翻译成可识别的机器语言(如:二进制)

苹果官方文档-runtime相关

2、Runtime的版本

  • 老版本,legacy version, OC 1.0 ,__OBJC__,-old
  • 新版本,modern version, OC 2.0 ,__OBJC2__,-new

3、Runtime的使用

运行时动态库 Runtime System Library 通过 编译器 compiler编译之后,提供了 Framework&ServiceRuntime API 供OC使用。

我们经常在OC中调用@selector(),其实就是在和runtime打交道了

  • OC上层方法 : @selector()
  • NSObject方法 : NSSelectorFromName
  • Runtime 底层api:sel_registerName

二、方法的本质

1、准备工作

测试代码:

// Person是继承自NSObject 自定义的类
Person *person = [Person alloc];

[person sayHello];


//定义一个void fly() {···},直接调用方法
fly();

通过clang手段:

兼容编译(代码少):clang -rewrite-objc main.m -o main.cpp

完整编译(不报错):xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp

2、方法的底层编译

看一下底层编译成什么:

Person *person = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("alloc"));

((void (*)(id, SEL))(void *)objc_msgSend)((id)person, sel_registerName("sayHello"));

fly();

解析:

  • ((Person *(*)(id, SEL))(void *)objc_msgSend) ((void (*)(id, SEL))(void *)objc_msgSend) 都是 类型强转
  • (id)objc_getClass("Person")拿到Person类
  • sel_registerName("alloc")sel_registerName("sayHello") 都是 调用方法,好比@selector()
  • 定义的C函数fly()clang后,并没有编译成objc_msgSend函数去调用。因为发送消息就是查找函数实现的过程,C函数可以直接通过函数名(指针)找到,并不需要这一步。

重点即:objc_msgSend(id,sel) = 发送消息(消息接收者,方法编号)

3、方法的本质

由底层编译可以看出,我们调用方法,在底层会变成objc_msgSend函数的调用。也就是说:

方法的本质就是发送消息

4、给不同的接受者发消息

假定条件: 有一个子类 Person,实例方法:run ,类方法:jump 有一个父类 People,实例方法:sayHi,类方法:sayBey

4.1 给对象发消息
//person的角度
objc_msgSend(person, sel_registerName("run"));
4.2 给类发消息
//person的角度
objc_msgSend(objc_getClass("Person"), sel_registerName("jump"));
4.3 给父类发消息(实例方法)

给父类发消息,要用另一个函数objc_msgSendSuper,并且要用到objc_super这个结构体

struct objc_super {
    //只看oc2版本需要的2个参数 
    __unsafe_unretained _Nonnull id receiver;  
    //··· 
    __unsafe_unretained _Nonnull Class super_class;
 	//··· 
};
//person 的角度
struct objc_super mySuper;
mySuper.receiver = person;
mySuper.super_class = [Person class];
objc_msgSendSuper(&mySuper, @selector(sayHi));
4.3 给父类发消息(类方法)
//person 的角度
struct objc_super myClassSuper;
myClassSuper.receiver = [Person class];
myClassSuper.super_class = class_getSuperclass(object_getClass([Person class]));// 元类
objc_msgSendSuper(&myClassSuper, sel_registerName("sayBey"));