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

《目录-iOS & OpenGL & OpenGL ES & Metal》html

对象和类以前已经分析过了,今天来分析一下方法,说到方法就不得不探究一下Runtime了~c++

1、Runtime

一、Runtime的定义

Runtime是一套API。api

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

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

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

运行时 & 编译时iphone

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

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

苹果官方文档-runtime相关oop

二、Runtime的版本

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

三、Runtime的使用

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

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

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

2、方法的本质

一、准备工做

测试代码:

// 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
复制代码

二、方法的底层编译

看一下底层编译成什么:

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) = 发送消息(消息接收者,方法编号)

三、方法的本质

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

方法的本质就是发送消息

四、给不一样的接受者发消息

假定条件: 有一个子类 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"));
复制代码
相关文章
相关标签/搜索