0%

iOS 开发之 Runtime(一) -- Runtime 初识

什么是Runtime?

Runtime 是由 C、 C++、 汇编共共同组成的 为 iOS 提供运行时功能的一套 API, 其中最主要的就是消息机制。
可以查看苹果的官网 Objective-C Runtime Programming Guide

运行时释义

  • 运行时,是在代码运行的时候,将对象等装载到内存中,通过方法名动态查找实现的函数。
  • 对比 C,C 语言在函数编译阶段会决定调用哪个函数,Rumtime 是在运行时根据函数的名称查找需要调用的哪个函数。

编译时释义

编译时就是在编译器,将高级语言编译成可以被计算机识别的机器语言。

Runtime 的底层库关系

Runtime 底层库的关系

Runtime 解析

简单举例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

#import <Foundation/Foundation.h>
#import "SCPerson.h"

void sayHello() {
NSLog(@"%s", __func__);
}

int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
SCPerson *person = [[SCPerson alloc] init];
[person sayHello];
sayHello();
}

return 0;
}

在 SCPerson.m 中 没有实现 sayHello, 在编译时,这个并不会报错,但是在运行时,会因为找不到 sayHello 发放报错.

利用 clang 来编译 main.m 文件,来查看底层代码

1
2
3
4
5
# 这个是简单的编译
clang -rewrite-objc main.m -o main.cpp

# 这种编译方式可以,减少警告
xcrun -sdk iphoneos clang -arch arm64 -rewrite main.m -o main.c++

我们可以看下编译过后 C 代码如下:

Main-Clang-Rumtime

其中

1
2
3
4
5
6
7
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
SCPerson *person = ((SCPerson *(*)(id, SEL))(void *)objc_msgSend)((id)((SCPerson *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("SCPerson"), sel_registerName("alloc")), sel_registerName("init"));
((void (*)(id, SEL))(void *)objc_msgSend)((id)person, sel_registerName("sayHello"));
}
return 0;
}

可以看出 Objective-C 调用方法的本质是通过 objc_messageSend 通过方法名 sel_registerName, 调用对象的实例方法。所以我们可以看出OC 方法的本质其实就是发送消息

(id)objc_getClass("SCPerson") 这个就是消息接受者
sel_registerName("alloc") 这个就是方法编号

通过

1
typedef struct objc_object SCPerson;

可以看出 OC 对象的本质,其实是一个结构体.

带着问题看本质

  • 如何通过方法编号,查询到方法

为了更方便我们查看方法的本质,我们最好先搭建一套 的环境

-------------本文结束感谢您的阅读-------------