Runtime 学习之介绍
OC 面向对象特性和动态性的的基石是 runtime
-
runtime 怎么是面向对象特性的基石?我们知道面向对象有3大特性:封装,继承,多态。OC类是不能直接编译成汇编语言的,需要先编译成C语言,而这里的C语言是用 runtime 来实现的。
-
封装:对数据和操作整合成一个有机整体。
// 我们可以看到添加属性和方法用到了 runtime 的 API static NSString * _I_Person_name(Person * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_Person$_name)); } extern "C" __declspec(dllimport) void objc_setProperty (id, SEL, long, id, bool, bool); static void _I_Person_setName_(Person * self, SEL _cmd, NSString *name) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct Person, _name), (id)name, 0, 1); }` ```
-
继承:子类拥有父类的成员变量和方法。runtime 的消息传递实现了这种继承关系。
-
多态:父类指针可以指向子类对象,定义一个方法时,参数可以定义为父类类型,传子类类型,相同的消息达到不同的效果。runtime 会动态检查对象的类型。
-
-
runtime 怎么是动态性的基石?
-
动态类型
动态类型即 id 类型,与动态类型相对的是静态类型。例如:NSString 等,静态类型在编译期会进行类型检查,若不对会报警告。而动态类型是在运行时根据语境来确定类型。
@property(weak) id <xxx> delegate
我们可以把任意类型赋值给 delegate,且不会报警告
-
动态绑定
int main() { func(); } void func(void) {}
我们通过分析汇编代码发现,执行 func() 时,汇编代码会让你跳转到 func 的实现位置处,意思是执行 func 函数。而动态语言,执行 func() 时,汇编代码只是一段发送消息的代码,并没有让你跳转到 func 位置处。所以,OC 是在运行时进行函数调用。
-
动态加载
动态加载指的是按需加载资源,例如:分类在运行期添加方法到类方法列表里;KVO 运行期创建一个中间类;动态添加方法,动态创建类等
-
runtime 有两个版本 modern, legacy
-
modern 只支持 OC 2.0 和 64 位机型
-
legacy 只支持 OC 1.0 和 32 位机型
-
两者的主要区别是:legacy 在类的实例变量布局发生改变时,需要重新编译。而 modern 不需要。