描述
OC
语言是一门动态语言
,会将程序的一些决定工作从编译期
推迟到运行期
。 由于OC语言运行时
的特性,所以其不只需要
依赖编译器
,还需要依赖运行时环境
。
OC
语言在编译期
都会被编译为C语言的Runtime
代码,二进制执行过程
中执行的都是C语言代码
。而OC
的类本质
上都是结构体
,在编译时
都会以结构体
的形式被编译到二进制
中。Runtime
是一套由C、C++、汇编
实现的API
,所有的方法调用
都叫做发送消息
。
根据Apple
官方文档的描述,目前OC运行时分为两个版本,Modern
和Legacy
。二者的区别在于Legacy
在实例变量
发生改变后,需要重新编译其子类
。Modern
在实例变量
发生改变后,不需要
重新编译其子类
。
Runtime不只是一些C语言的API,其由Class
、Meta Class
、Instance
、Class Instance
组成,是一套完整的面向对象
的数据结构
。所以研究Runtime
整体的对象模型,比研究API是怎么实现的更有意义。
运行时编译时区别
运行时
是代码跑起来,被装载到内存中
的过程,如果此时出错,则程序会崩溃
,是一个动态阶段
编译时
是源代码
翻译成机器能识别的代码的过程,主要是对语言进行最基本的检查报错,即词法分析
、语法分析
等,是一个静态阶段
使用Runtime
Runtime是一个共享动态库,其目录位于/usr/include/objc,由一系列的C函数和结构体构成。和Runtime系统发生交互的方式有三种,一般都是用前两种:
使用OC源码
直接使用上层OC源码,底层会通过Runtime为其提供运行支持,上层不需要关心Runtime运行。
NSObject
在OC代码中绝大多数的类都是继承自NSObject的,NSProxy类例外。Runtime在NSObject中定义了一些基础操作,NSObject的子类也具备这些特性。
Runtime动态库
上层的OC源码都是通过Runtime实现的,我们一般不直接使用Runtime,直接和OC代码打交道就可以。
使用Runtime需要引入下面两个头文件,一些基础方法都定义在这两个文件中。
#import <objc/runtime.h>
#import <objc/message.h>
runtime
的使用
有以下三种方式,其三种实现方法与编译层和底层的关系如图所示
通过
OC代码
,例如[person sayNB]
通过
NSObject方法
,例如isKindOfClass
通过
Runtime API
,例如class_getInstanceSize
、class_getInstanceMethod
其中的compiler
就是我们了解的编译器
,即LLVM
,例如OC的alloc
对应底层的objc_alloc
, runtime system libarary
就是底层库