1. 对象
La 类
relation isa
entre
Grâce à la recherche sur la nature des objets OC et isa , nous avons constaté que chaque objet a des variables membres isa
, et aujourd'hui nous l'utilisons comme entrée pour étudier 对象
la 类
relation isa
entre et.
Pas grand chose à dire, sur le code, créez d'abord deux classes YJPerson(继承NSObject)
, YJTeacher(继承YJPerson)
, pour les tests ; comme suit :
// YJPerson
@interface YJPerson : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;
@end
// YJTeacher
@interface YJTeacher : YJPerson
@property (nonatomic, copy) NSString *subject;
@end
1.1 est une position de course
/// isa 链路
void testIsaChain (id obj)
{
// 对象所属类 - 对象的isa指向
Class cls = object_getClass(obj);
// 元类 - 类的isa指向
Class metaCls = object_getClass(cls);
// 根元类 - 元类的isa指向
Class rootCls = object_getClass(metaCls);
// 根根元类 - 根元类的isa指向
Class metaOfRootCls = object_getClass(rootCls);
NSLog(@"对象的 isa -> : %@", obj);
NSLog(@"类的的 isa -> : %@, %p", cls, cls);
NSLog(@"元类的 isa -> : %@, %p", metaCls, metaCls);
NSLog(@"根元类的 isa -> : %@, %p", rootCls, rootCls);
NSLog(@"根根元类的 isa -> : %@, %p\n", metaOfRootCls, metaOfRootCls);
}
in main(int argc, const char * argv[]) {
@autoreleasepool {
// isa 链路测试
testIsaChain(NSObject.new);
testIsaChain(YJPerson.new);
testIsaChain(YJTeacher.new);
NSLog(@"Hello, World!");
}
return 0;
}
résultat d'impression :
En imprimant les résultats, on conclut que :
对象 -isa-> 类 -isa-> 元类 -isa-> 根元类 -isa-> 根元类自己
1.2 bitmap superclasse
/// super class 链路
void testSuperClassChain (Class cls)
{
Class superCls = class_getSuperclass(cls);
NSLog(@"父类 : %@, %p", superCls, superCls);
if (!superCls) {
NSLog(@"\n");
return;
}
testSuperClassChain(superCls);
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 类的 superclass 链路
Class objCls = NSObject.class;
NSLog(@"类 : %@, %p", objCls, objCls);
testSuperClassChain(objCls);
Class personsCls = YJPerson.class;
NSLog(@"类 : %@, %p", personsCls, personsCls);
testSuperClassChain(personsCls);
Class teacherCls = YJTeacher.class;
NSLog(@"类 : %@, %p", teacherCls, teacherCls);
testSuperClassChain(teacherCls);
// 原类的 superclass 链路
Class objMetaClass = object_getClass(objCls);
NSLog(@"%@ 的元类 : %@, %p", objCls, objMetaClass, objMetaClass);
testSuperClassChain(objMetaClass);
Class personMetaClass = object_getClass(personsCls);
NSLog(@"%@ 的元类 : %@, %p", personsCls, personMetaClass, personMetaClass);
testSuperClassChain(personMetaClass);
Class teacherMetaClass = object_getClass(teacherCls);
NSLog(@"%@ 的元类 : %@, %p", teacherCls, teacherMetaClass, teacherMetaClass);
testSuperClassChain(teacherMetaClass);
}
return 0;
}
Résultat de sortie :
Grâce à l'analyse, nous pouvons constater superclass 链路
qu'il peut être divisé en deux catégories:
-
类的
lien superclasse :类
-supercls->父类
-supercls->...
-supercls->NSObject类
-supercls->nil
-
类的元类
lien superclasse :类的元类
-supercls->父类的元类
-supercls->...
-supercls->NSObject的元类
-supercls->NSObject类
-supercls->nil
Enfin, pointez sur l'organigramme :
Jusqu'à présent, j'ai une compréhension claire de la relation de lien avec et de la 对象
relation de chaîne d'héritage 类
avec .isa
类
superclass
Cependant, à 类
quoi ressemble la structure interne des membres, nous ne le savons toujours pas. Continuez à explorer. . .
2. Analyse structurelle des classes
Basé sur objc4 (version 838)objc_class 源码
struct objc_class : objc_object {
// 省略 ...
// Class ISA; // isa 继承自 objc_object 8字节
Class superclass; // 8字节
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
// 省略 ...
class_rw_t *data() const {
return bits.data();
}
// 省略 ...
}
-
isa
Membre : hérité deobjc_object
,isa
occupe des8
octets -
superclass
成员:Class
类型,Class
是typedef struct objc_class *Class;
定义的,是一个指针
,占8
字节 -
cache
成员:简单从类型class_data_bits_t
目前无法得知,而class_data_bits_t
是一个结构体
类型,结构体
的内存大小
需要根据内部的成员
来确定 -
bits
成员:只有首地址
经过上面3个属性的内存大小总和的平移,才能获取到bits
2.1 计算 cache
的内存大小
cache_t
的定义:
struct cache_t {
private:
explicit_atomic<uintptr_t> _bucketsAndMaybeMask;
union {
struct {
explicit_atomic<mask_t> _maybeMask;
#if __LP64__
uint16_t _flags;
#endif
uint16_t _occupied;
};
explicit_atomic<preopt_cache_t *> _originalPreoptCache;
};
// 省略无关代码。。。
cache_t
分析:
cache_t
有两个成员:_bucketsAndMaybeMask
和 一个联合体
-
_bucketsAndMaybeMask
是uintptr_t
无符长整型占8字节
-
联合体
里面有两个成员变量结构体
和_originalPreoptCache
(联合体的内存大小由成员变量中的最大成员变量的类型决定)-
_originalPreoptCache
是个指针占8字节
-
结构体
中有_maybeMask
,_flags
,_occupied
。_maybeMask
是uint32_t
占4字节
_flags
是uint16_t
各占2字节
_occupied
是uint16_t
各占2字节
结构体
大小是4 + 2 + 2 = 8字节
-
-
cache_t
的内存大小是8 + 8 = 16 字节
2.2 获取 bits
我们已经知道了类结构中 isa(8字节)
、superclass(8字节)
、cache(16字节)
的大小,接下来只需要通过地址偏移8 + 8 + 16 = 32
,即可得到 bits
的地址
- 其中的
data()
获取数据,是由objc_class
提供的方法
- 从源码 或 lldb调试中都可以看出
bits.data()
中存储的信息,其类型是class_rw_t
,也是一个结构体类型。但我们还是没有看到属性列表、方法列表
等,需要继续往下探索
2.3 探索 属性列表,即 property_list
通过查看class_rw_t
定义的源码发现,结构体
中有提供
相应的方法
去获取 属性列表、方法列表
等,如下所示:
在获取bits
并打印bits
信息的基础上,通过class_rw_t
提供的方法,继续探索 bits
中的属性列表
,以下是lldb 探索的过程图示:
-
p $2.properties()
命令中的propertoes
方法是由class_rw_t
提供的,返回值类型是property_array_t
-
list
的类型是property_list_t,是一个指针
,所以通过p *$5
获取内存中的信息
,同时也证明bits
中存储了property_list
,即属性列表
2.4 探索 方法列表,即 methods_list
在前文中提到的 YJPerson
中添加两个方法:实例方法sayHello
,类方法 eat
// YJPerson.h
@interface YJPerson : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age;
- (void)sayHello;
+ (void)eat;
@end
// YJPerson.m
@implementation YJPerson
- (void)sayHello { }
+ (void)eat { }
@end
2.4.1 方法的获取
参照属性列表的获取,我们来获取方法列表,如下图:
这里和属性获取不太一样,属性列表 property_list_t
里存储的是 property_t
,而 property_t
是这样的:
struct property_t {
const char *name;
const char *attributes;
};
所以属性通过索引可以直接输出属性的信息。而
方法列表method_list_t
存储的是 method_t
,method_t
是这样的:
struct method_t {
// 省略。。。
// 方法描述结构体
struct big {
SEL name;
const char *types;
MethodListIMP imp;
};
// 省略。。。
// big()方法 返回方法描述结构体
big &big() const {
ASSERT(!isSmall());
return *(struct big *)this;
}
// 省略。。。
}
所以需要在获取 method_t
之后再调用 big()
方法,才能正常输出
2.4.2 方法分析
通过打印 method_list_t
中的每个 method_t
,发现并没有类方法eat
;由此可知:method_list_t
存储的是类的对象方法。那么 类方法eat
存在哪儿呢?不捉急,后续篇章为您揭秘。。。
总结
Il y a des variables isa
, superclass
, , chche
et membres dans la classe. Au cours du processus d'exploration, on constate que les familiers , , , etc. sont stockés, ce qui ouvre notre compréhension . Nous continuerons à explorer la classe plus tard, alors restez à l'écoutebits
bits
bits
属性列表
方法列表
成员变量列表
协议列表
类