运行时简介
Objective-C
语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理。
对于Objective-C
来说,这个运行时系统就像一个操作系统一样:它让所有的工作可以正常的运行。Runtime
基本上是用C
和汇编
写的,这个库使得C
语言有了面向对象的能力。
在Runtime
中,对象可以用C
语言中的结构体表示,而方法可以用C
函数来实现,另外再加上了一些额外的特性。这些结构体和函数被runtime
函数封装后,让OC
的面向对象编程变为可能。
找出方法的最终执行代码:当程序执行[object doSomething]
时,会向消息接收者(object)
发送一条消息(doSomething)
,runtime
会根据消息接收者是否能响应该消息而做出不同的反应。
类与对象基础数据结构
Objective-C
中的类是由Class
类型结构表示的,它是一个指向objc_class
结构体的指针,如下,
在objc.h
中
/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;
在runtime.h
中可以查看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;//类的版本信息,默认为0
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;
/* Use `Class` instead of `struct objc_class *` */
objc_object
objc_object
是一个表示类的实例的结构体指针,在objc.h
中可以查看它的定义,如下
/// 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;
由上可以看到,这个结构只有一个指针,即指向其类的isa
指针。
当我们向一个Objective-C
对象发送消息时,runtime
库会根据实例对象的isa
指针找到这个实例对象所属的类。而后,runtime
库会在这个类的方法列表以及其父类的方法列表去寻找与消息对应的selctor
所指向的方法,最后运行这个方法。
元类Meta Class
meta-class
是一个类本身对象所属的类。
- 所有的类本身也是一个对象,我们可以向这个对象发送消息,即调用类方法。
- 既然是对象,那么它也是一个
objc_object
指针,包含一个指向其类的isa
指针,那么这个isa
指针又指向哪里呢? - 为了调用类方法,这个类的
isa
指针必须指向一个包含这些类方法的一个objc_class
结构体。这就引出了meta-class
的概念,meta-class
中存储着一个类的所有类方法。
所以,调用类方法的这个类对象的isa
指针指向的就是meta-class
。
-
当我们向一个对象发送消息时,
runtime
会在这个对象所属的这个类的方法列表中查找方法;而向一个类发送消息时,会在这个类的meta-class
的方法列表中查找。 -
再深入一下,
meta-class
也是一个类,也可以向它发送一个消息,那么它的isa
又是指向哪里呢?为了不让这种结构无限延伸下去,Objective-C
的设计者让所有的meta-class
的isa
指向基类的meta-class
,以此作为它们的所属类。
任何
NSObject
继承体系下的meta-class
都使用NSObject
的meta-class
作为自己的所属类,
而基类的meta-class
的isa
指针是指向它自己。
通过上面的描述,再加上对objc_class
结构体中super_class
指针的分析,我们就可以描绘出类及相应meta-class
类的一个继承体系图了,如下
Category
Category
是表示一个指向分类的结构体的指针,如下,
在runtime.h
中
struct objc_category {
char * _Nonnull category_name OBJC2_UNAVAILABLE;//分类名
char * _Nonnull class_name OBJC2_UNAVAILABLE;//分类所属的类名
struct objc_method_list * _Nullable instance_methods OBJC2_UNAVAILABLE;//实例方法列表
struct objc_method_list * _Nullable class_methods OBJC2_UNAVAILABLE;//类方法列表
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;、//分类所实现的协议的列表
} OBJC2_UNAVAILABLE;
这个结构体主要包含了分类定义的实例方法与类方法,其中instance_methods
列表是objc_class
中方法列表的一个子集,而class_methods
列表是元类方法列表的一个子集。
可以发现,类别中没有ivar
成员变量指针,也就意味着:类别中不能够添加实例变量和属性。
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 该类的成员变量链表
上面的内容来源自宇杰笔记的这一篇文章:iOS运行时(Runtime)详解+Demo。我也是一边理解一边写的。
网友评论