1. Class (类)
1. Class (类)的本质
在 objc/runtime.h 中,Class(类) 被定义为指向 objc_class 结构体的指针,objc_class 结构体的数据结构如下:
typedef struct objc_class *Class;
struct objc_class {
Class _Nonnull isa; // objc_class 结构体的实例指针
#if !__OBJC2__
Class _Nullable super_class; // 指向父类的指针
const char * _Nonnull name; // 类的名字
long version; // 类的版本信息,默认为 0
long info; // 类的信息,供运行期使用的一些位标识
long instance_size; // 该类的实例变量大小;
struct objc_ivar_list * _Nullable ivars; // 该类的实例变量列表
struct objc_method_list * _Nullable * _Nullable methodLists; // 方法定义的列表
struct objc_cache * _Nonnull cache; // 方法缓存
struct objc_protocol_list * _Nullable protocols; // 遵守的协议列表
#endif
};
objc_class 结构体的第一个成员变量是 isa 指针,isa 指针 保存的是objc_class结构体的实例指针,换言之,Class(类)的本质就是一个对象,称之为 类对象。
2. Method (方法)
objc_class 结构体的 struct objc_method_list **methodLists(方法列表)结构体用来存储方法的列表
struct objc_method_list {
struct objc_method_list * _Nullable obsolete;
int method_count;
#ifdef __LP64__
int space;
#endif
/* variable length structure */
struct objc_method method_list[1];
}
在 objc/runtime.h 中, Method(方法)被定义为指向objc_method 结构体的指针,objc_method 结构体数据结构:
typedef struct objc_method *Method;
struct objc_method {
SEL _Nonnull method_name; // 方法名
char * _Nullable method_types; // 方法类型
IMP _Nonnull method_imp; // 方法实现
};
objc_method结构体中包含了 method_name(方法名),method_types(方法类型:方法的参数类型和返回值类型) 和 method_imp(方法实现)。Method 将 SEL(方法声明) 和 IMP(方法实现)关联起来(键值对:SEL: IMP),当对一个对象发送消息时,会通过给出的 SEL(方法声明)去找到 IMP(方法实现),然后执行。
1. SEL (方法声明)
在 objc/objc.h中, SEL(方法声明)被定义为指向 objc_selector结构体的指针。
typedef struct objc_selector *SEL;
在runtime相关头文件中并没有找到明确的定义。通过测试得出: SEL 只是一个保存方法名的字符串。Objective-C 在编译时,会依据每一个方法的名字、参数序列,生成一个唯一的整型标识(Int类型的地址),这个标识就是 SEL。
2. IMP (方法实现)
在 objc/objc.h中,IMP(方法实现)被定义为指向函数的指针。
#if !OBJC_OLD_DISPATCH_PROTOTYPES
typedef void (*IMP)(void /* id, SEL, ... */ );
#else
typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...);
#endif
IMP 的实质是一个函数指针,所指向的就是方法的实现。IMP用来找到函数地址,然后执行函数。
IMP 指向的函数函第一个参数是指向self的指针(如果是实例方法,则是类实例的内存地址;如果是类方法,则是指向元类的指针),第二个参数是 SEL 类型的方法选择器,接下来是方法的实际参数列表,并返回一个 id。通过一组 id和 SEL 参数就能确定唯一的方法实现地址。也就是说 IMP 是消息最终调用的执行代码,是方法真正的实现代码 。
3. method_types (方法类型)
method_types 是个字符串,用来存储方法的参数类型和返回值类型。
3. Ivar (实例变量)
objc_class 结构体的 struct objc_ivar_list *ivars(实例变量列表)中结构体用来存储成员变量的列表。
struct objc_ivar_list {
int ivar_count;
#ifdef __LP64__
int space;
#endif
/* variable length structure */
struct objc_ivar ivar_list[1];
}
在 objc/runtime.h 中, Ivar(实例变量)被定义为指向objc_ivar 结构体的指针,objc_ivar 结构体数据结构:
typedef struct objc_ivar *Ivar;
struct objc_ivar {
char * _Nullable ivar_name; //实例变量名称
char * _Nullable ivar_type; //实例变量类型
int ivar_offset; //基地址偏移字节
#ifdef __LP64__
int space;
#endif
}
4. Cache (方法缓存)
objc_class 结构体的 struct objc_cache *cache(方法缓存)。在 objc/runtime.h 中,Cache(方法缓存)被定义为指向objc_cache 结构体的指针,objc_cache 结构体数据结构:
typedef struct objc_cache *Cache
struct objc_cache {
unsigned int mask /* total = mask + 1 */;
unsigned int occupied;
Method _Nullable buckets[1];
}
Cache为方法调用的性能进行优化,每当实例对象接收到一个消息时,它不会直接在 isa 指针指向的类的方法列表中遍历查找能够响应的方法,因为每次都要查找效率太低了,而是优先在Cache中查找。
Runtime系统会把被调用的方法存到Cache中,如果一个方法被调用,那么它有可能今后还会被调用,下次查找的时候就会效率更高。
5. Protocol (协议)
objc_class 结构体的struct objc_protocol_list *protocols(遵守的协议列表),中存放的元素就Protocol(协议);
typedef struct objc_object Protocol;
struct objc_protocol_list {
struct objc_protocol_list * _Nullable next;
long count;
__unsafe_unretained Protocol * _Nullable list[1];
};
在 objc/runtime.h 中, Protocol(协议)被定义为objc_object结构体。
#ifdef __OBJC__
@class Protocol;
#else
typedef struct objc_object Protocol;
#endif
2. Object (对象)
在 objc/objc.h 中,Object(对象)被定义为 objc_object 结构体,其数据结构如下:
struct objc_object {
Class _Nonnull isa; // objc_class 结构体的实例指针
};
typedef struct objc_object *id;
objc_object 结构体只包含一个 Class 类型的 isa 指针。即, objc_object 结构体唯一保存的就是它所属 Class(类)的地址。
3. Meta Class (元类)
对象(objc_object 结构体) 的 isa 指针 指向的是对应的 类对象(object_class 结构体)。那么 类对象(object_class 结构体)的 isa 指针 又指向 类对象 自身的 Meta Class(元类)。
Runtime 中把类对象所属类型就叫做 Meta Class(元类),用于描述类对象本身所具有的特征,而在元类的 methodLists 中,保存了类的方法链表,即所谓的「类方法」。并且类对象中的 isa 指针 指向的就是元类。每个类对象有且仅有一个与之相关的元类。
4. 对象、类、元类之间的关系
-
isa 指针:- 实例对象的
isa 指针指向对应的类对象,类对象的isa 指针指向对应的元类。(所有)元类的isa 指针最终指向根(NSObject)元类。 - 注意:(所有)元类包括
根(NSObject)元类,即,根元类 的isa 指针指向自己。
- 实例对象的
-
父类指针: -
类对象的父类指针指向父类对象,父类对象的父类指针指向根类(NSObject)对象,根类(NSObject)对象的父类指针指向nil; -
元类的父类指针指向父类对象的元类,父类对象的元类的父类指针指向根(NSObject)元类,根(NSObject)元类的父类指针指向根类(NSObject)对象,根类(NSObject)对象的父类指针指向 nil 。