今天,我打算说说自己对于Objective-C中的类的理解。Objective-C中的类在编译的时候首先会编译成C语言,这时候类就变成了C语言的结构体了。
1. Class的实际结构
struct _class_t {
struct _class_t *isa; // isa指针
struct _class_t *superclass; // 父类
void *cache;
void *vtable;
struct _class_ro_t *ro; // 包含class的信息
};
/// 具体的_class_ro_t结构如下
struct _class_ro_t {
unsigned int flags;
unsigned int instanceStart; // 实例对象的起始地址
unsigned int instanceSize; // 实例对象占用的内存大小
unsigned int reserved;
const unsigned char *ivarLayout;
const char *name; // 类名
const struct _method_list_t *baseMethods; // 方法列表
const struct _objc_protocol_list *baseProtocols; // 协议列表
const struct _ivar_list_t *ivars; // ivar列表
const unsigned char *weakIvarLayout; // 猜测是weak修饰的ivar
const struct _prop_list_t *properties; // 属性列表
};
我们先定义两个个简单的OC类Father和Son
- Father
@interface Father : NSObject
@property (nonatomic, copy) NSString *name;
@end
@implementation Father
+ (instancetype)fatherWithName:(NSString *)name {
Father *father = [[[self class] alloc] init];
father.name = name;
return father;
}
- (instancetype)initWithName:(NSString *)name {
if (self = [[[self class] alloc] init]) {
self.name = name;
}
return self;
}
@end
- Son
@interface Son : Father
{
NSUInteger _age;
}
@end
@implementation Son
+ (instancetype)sonWithName:(NSString *)name age:(NSUInteger)age {
Son *son = [super fatherWithName:name];
son->_age = age;
return son;
}
- (instancetype)initWithName:(NSString *)name age:(NSUInteger)age {
if (self = [super initWithName:name]) {
self->_age = age;
}
return self;
}
@end
我们通过clang -rewrite-objc main.m能得到重写后的纯C代码,并找到Father和Son的_class_t
结构
// Father
struct _class_t OBJC_CLASS_$_Father = {
0, // &OBJC_METACLASS_$_Father,
0, // &OBJC_CLASS_$_NSObject,
0, // (void *)&_objc_empty_cache,
0, // unused, was (void *)&_objc_empty_vtable,
&_OBJC_CLASS_RO_$_Father,
};
// Son
struct _class_t OBJC_CLASS_$_Son = {
0, // &OBJC_METACLASS_$_Son,
0, // &OBJC_CLASS_$_Father,
0, // (void *)&_objc_empty_cache,
0, // unused, was (void *)&_objc_empty_vtable,
&_OBJC_CLASS_RO_$_Son,
};
再来看看_class_ro_t定义些什么
- Father
static struct _class_ro_t _OBJC_CLASS_RO_$_Father = {
0, __OFFSETOFIVAR__(struct Father, _name), sizeof(struct Father_IMPL),
(unsigned int)0,
0,
"Father", // 类名
(const struct _method_list_t *)&_OBJC_$_INSTANCE_METHODS_Father, // 方法列表
0, // 协议列表
(const struct _ivar_list_t *)&_OBJC_$_INSTANCE_VARIABLES_Father, // ivar列表
0, // weak修饰的ivar
(const struct _prop_list_t *)&_OBJC_$_PROP_LIST_Father, // 属性列表
};
- Son
static struct _class_ro_t _OBJC_CLASS_RO_$_Son = {
0, __OFFSETOFIVAR__(struct Son, _age), sizeof(struct Son_IMPL),
(unsigned int)0,
0,
"Son", // 类名
(const struct _method_list_t *)&_OBJC_$_INSTANCE_METHODS_Son, // 方法列表
0, // 协议列表
(const struct _ivar_list_t *)&_OBJC_$_INSTANCE_VARIABLES_Son, // ivar列表
0, // weak修饰的ivar
0, // 属性列表
};
2. _class_ro_T中的值
在定义完结构体之后,我们在看看其中的成员方法列表,ivar列表,属性列表中分别都有什么:
-
Fathe
-
成员方法列表
static struct /*_method_list_t*/ { unsigned int entsize; // sizeof(struct _objc_method) unsigned int method_count; struct _objc_method method_list[3]; } _OBJC_$_INSTANCE_METHODS_Father = { sizeof(_objc_method), 3, {{(struct objc_selector *)"initWithName:", "@24@0:8@16", (void *)_I_Father_initWithName_}, {(struct objc_selector *)"name", "@16@0:8", (void *)_I_Father_name}, {(struct objc_selector *)"setName:", "v24@0:8@16", (void *)_I_Father_setName_}} };
Father里面有3个成员方法,其中name和setName:这两个方式是name属性的set和get方法,我们用
@property
修饰属性的时候,编译器会在编译的时候为我们生成相应的set和get方法 -
ivar成员变量列表
static struct /*_ivar_list_t*/ { unsigned int entsize; // sizeof(struct _prop_t) unsigned int count; struct _ivar_t ivar_list[1]; } _OBJC_$_INSTANCE_VARIABLES_Father = { sizeof(_ivar_t), 1, {{(unsigned long int *)&OBJC_IVAR_$_Father$_name, "_name", "@\"NSString\"", 3, 8}} };
在Father里面,我们只用@property修饰器定义了一个成员属性,如果没有主动的定义_name成员变量的话,编译器会为我们主动生成_name这个成员变量。
-
属性列表
static struct /*_prop_list_t*/ { unsigned int entsize; // sizeof(struct _prop_t) unsigned int count_of_properties; struct _prop_t prop_list[1]; } _OBJC_$_PROP_LIST_Father = { sizeof(_prop_t), 1, {{"name","T@\"NSString\",C,N,V_name"}} };
可以看到,属性列表里面有我们定义的name
Father的成员变量中的
- (NSString *)name
方法返回的是ivar列表中的_name成员变量,通过_name的偏移值来获取。 -
-
Son
-
成员方法列表
static struct /*_method_list_t*/ { unsigned int entsize; // sizeof(struct _objc_method) unsigned int method_count; struct _objc_method method_list[1]; } _OBJC_$_INSTANCE_METHODS_Son = { sizeof(_objc_method), 1, {{(struct objc_selector *)"initWithName:age:", "@32@0:8@16Q24", (void *)_I_Son_initWithName_age_}} };
Son里面只有1个成员方法和Father相比少了两个set和get方法
-
ivar成员变量列表
static struct /*_ivar_list_t*/ { unsigned int entsize; // sizeof(struct _prop_t) unsigned int count; struct _ivar_t ivar_list[1]; } _OBJC_$_INSTANCE_VARIABLES_Son = { sizeof(_ivar_t), 1, {{(unsigned long int *)&OBJC_IVAR_$_Son$_age, "_age", "Q", 3, 8}} };
Son只有一个成员变量,因为代码中直接定义了这个_age成员变量
Son中没有使用@property修饰器来定义一个属性,因此Son中的属性列表是空的。
-
3. 设置_class_t的信息
👆只是定义了类结构的信息,下面将对类结构的一些属性进行赋值
-
Father
static void OBJC_CLASS_SETUP_$_Father(void ) { OBJC_METACLASS_$_Father.isa = &OBJC_METACLASS_$_NSObject; OBJC_METACLASS_$_Father.superclass = &OBJC_METACLASS_$_NSObject; OBJC_METACLASS_$_Father.cache = &_objc_empty_cache; OBJC_CLASS_$_Father.isa = &OBJC_METACLASS_$_Father; OBJC_CLASS_$_Father.superclass = &OBJC_CLASS_$_NSObject; OBJC_CLASS_$_Father.cache = &_objc_empty_cache; }
这是对Father结构体进行赋值,这里面涉及到了
OBJC_METACLASS_$_Father
其实这是Father的metaclass,将OBJC_CLASS_$_Father
的isa指针指向其metaclass,再将父类指针指向NSObject -
Son
static void OBJC_CLASS_SETUP_$_Son(void ) { OBJC_METACLASS_$_Son.isa = &OBJC_METACLASS_$_NSObject; OBJC_METACLASS_$_Son.superclass = &OBJC_METACLASS_$_Father; OBJC_METACLASS_$_Son.cache = &_objc_empty_cache; OBJC_CLASS_$_Son.isa = &OBJC_METACLASS_$_Son; OBJC_CLASS_$_Son.superclass = &OBJC_CLASS_$_Father; OBJC_CLASS_$_Son.cache = &_objc_empty_cache; }
看起来和
OBJC_METACLASS_$_Father
好像没什么不一样的,但是其中将OBJC_CLASS_$_Son
的父类设置成了OBJC_CLASS_$_Father
并将其metaclass指向自己的OBJC_METACLASS_$_Son
注意:
OBJC_METACLASS_$_Father
和OBJC_METACLASS_$_Son
的isa指针都是指向OBJC_METACLASS_$_NSObject
但是OBJC_METACLASS_$_Son
的superclass指针是指向OBJC_METACLASS_$_Father
4. Metaclass
既然提到了metaclass,那么我们接下来继续看一下Father和Son这两个类的metaclass分别长什么样的
-
Father
struct _class_t OBJC_METACLASS_$_Father = { 0, // &OBJC_METACLASS_$_NSObject, 0, // &OBJC_METACLASS_$_NSObject, 0, // (void *)&_objc_empty_cache, 0, // unused, was (void *)&_objc_empty_vtable, &_OBJC_METACLASS_RO_$_Father, };
OBJC_METACLASS_$_Father
是一个_class_t结构体啊,再看看_OBJC_METACLASS_RO_$_Father
:static struct _class_ro_t _OBJC_METACLASS_RO_$_Father = { 1, sizeof(struct _class_t), sizeof(struct _class_t), (unsigned int)0, 0, "Father", // metaclass名 (const struct _method_list_t *)&_OBJC_$_CLASS_METHODS_Father, // 方法列表 0, // 协议列表 0, // ivar成员变量列表 0, // weak修饰的ivar 0, // 属性列表 };
Father的metaclass里面只有方法列表有值
static struct /*_method_list_t*/ { unsigned int entsize; // sizeof(struct _objc_method) unsigned int method_count; struct _objc_method method_list[1]; } _OBJC_$_CLASS_METHODS_Father = { sizeof(_objc_method), 1, {{(struct objc_selector *)"fatherWithName:", "@24@0:8@16", (void *)_C_Father_fatherWithName_}} };
OBJC_METACLASS_$_Father
的方法列表里面一个方法,该方法是我们定义的便利构造器,说明一个类的类方法是放在类的metaclass中的。 -
Son
struct _class_t OBJC_METACLASS_$_Son = { 0, // &OBJC_METACLASS_$_NSObject, 0, // &OBJC_METACLASS_$_Father, 0, // (void *)&_objc_empty_cache, 0, // unused, was (void *)&_objc_empty_vtable, &_OBJC_METACLASS_RO_$_Son, };
static struct _class_ro_t _OBJC_METACLASS_RO_$_Son = { 1, sizeof(struct _class_t), sizeof(struct _class_t), (unsigned int)0, 0, "Son", (const struct _method_list_t *)&_OBJC_$_CLASS_METHODS_Son, 0, 0, 0, 0, };
static struct /*_method_list_t*/ { unsigned int entsize; // sizeof(struct _objc_method) unsigned int method_count; struct _objc_method method_list[1]; } _OBJC_$_CLASS_METHODS_Son = { sizeof(_objc_method), 1, {{(struct objc_selector *)"sonWithName:age:", "@32@0:8@16Q24", (void *)_C_Son_sonWithName_age_}} };
是的,Son的类方法也是定义在metaclass中的。
第一次写,欢迎大牛提出意见,文中观点不太可靠,都是个人理解,不喜勿喷~~~
网友评论