什么是runtime
OC是一门动态语言,它是基于C语言的,它为C 添加了面向对象的特性。它将很多静态语言在编译和链接时期做的事放到了 runtime 运行时来处理.
runtime运用
- 在程序运行过程中,动态的创建类,动态添加、修改这个类的属性和方法
- 遍历一个类中所有的成员变量、属性、以及所有方法
- 消息传递、转发
在OC中的NSObject对象定义
@interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}
NSObject只有一个成员变量isa,它实际上是一个指向objc_class结构体的指针
// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;
// Represents an instance of a class.
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
- 由此可见可以看到Class、id 都是指针
- id是指向objc_object的一个指针
- objc_object有个isa指向objc_class的一个指针
- id和Class最后指向的都是objc_class这个结构体
objc_class结构体中的定义如下:
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE;
const char * _Nonnull name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
类就长这样子:
Class 也有一个 isa 指针,指向其所属的元类
super_class:指向其超类
name:是类名
version:是类的版本信息
info:是类的详情
instance_size:是该类的实例对象的大小
ivars:指向该类的成员变量列表
methodLists:指向该类的实例方法列表,它将方法选择器和方法实现地址联系起来。methodLists 是指向 objc_method_list 的指针,也就是说可以动态修改 methodLists 的值来添加成员方法,这也是 Category 实现的原理,同样解释了 Category 不能添加属性的原因。
cache:Runtime 系统会把被调用的方法存到 cache 中以便下次查找的时候效率更高
protocols:指向该类的协议列表
在runtime使用当中,我们经常需要用到的字段,它们的定义:
- isa 和Class对象,指向objc_class结构体的指针
- 类的实例对象的 isa 指向该类;该类的 isa 指向该类的 MetaClass
- MetaCalss的isa对象指向RootMetaCalss
- super_class Class对象指向父类对象
- 如果该类的对象已经是RootClass,那么这个super_class指向nil
- MetaCalss的SuperClass指向父类的MetaCalss
-
MetaCalss是RootMetaCalss,那么该MetaClass的SuperClass指向该对象的RootClass
OC的方法调用 Runtime会转化为消息发送,即 objc_msgSend(receiver, selector),即方法的调用者和方法选择器,当做参数传递.
方法的调用者会通过 isa 指针来找到其所属的类,然后在 cache 或者 methodLists 中查找该方法,找得到就跳到对应的方法去执行。
如果在类中没有找到该方法,则通过 super_class 往上一级超类查找
类方法被存储在元类中,Class 通过 isa 指针即可找到其所属的元类