序言
在OC面向对象编程中,我们每天都面对着创建对象,操作对象, 那对象究竟是什么?实例化的对象和类的本质又是什么?
目录
- clang查看OC底层的实现
- 源码分析
- 总结
一、clang查看OC底层的实现
新建文件main.m,在文件中添加如下代码,添加属性,类方法和实例方法,还有方法的调用。
#import <UIKit/UIKit.h>
@interface PSYPerson : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, copy) NSString *nickName;
@property (nonatomic, assign) BOOL isWorking;
+ (void)run;
- (void)run;
@end
@implementation PSYPerson
+ (void)run
{
NSLog(@"run class method printf");
}
- (void)run
{
NSLog(@"run instance method printf");
}
@end
int main(int argc, char * argv[]) {
@autoreleasepool {
PSYPerson *psy1 = [[PSYPerson alloc] init];
[psy1 run];
}
return 0;
}
使用rewrite将其转成C++代码,在终端执行如下命令,即可转成main.cpp文件,由于文件中import了UIKit,所以文件比较大(足有7万多行代码)。
xcrun -sdk iphoneos clang -rewrite-objc -F UIKit -fobjc-arc -arch arm64 main.m
可直接翻到最后查看自己编写的代码,最后转成了什么。在__DATA, __objc_classlist
的section段中,存放着类的列表,具体如下,类是以_class_t
的结构体方式存储。
//_class_t的定义
struct _class_t {
struct _class_t *isa;
struct _class_t *superclass;
void *cache;
void *vtable;
struct _class_ro_t *ro;
};
static struct _class_t *L_OBJC_LABEL_CLASS_$ [1] __attribute__((used, section ("__DATA, __objc_classlist,regular,no_dead_strip")))= {
&OBJC_CLASS_$_PSYPerson,
};
上来一些就是元类和类的初始化
extern "C" __declspec(dllimport) struct _class_t OBJC_METACLASS_$_NSObject;
// 元类部分
extern "C" __declspec(dllexport) struct _class_t OBJC_METACLASS_$_PSYPerson __attribute__ ((used, section ("__DATA,__objc_data"))) = {
0, // &OBJC_METACLASS_$_NSObject,
0, // &OBJC_METACLASS_$_NSObject,
0, // (void *)&_objc_empty_cache,
0, // unused, was (void *)&_objc_empty_vtable,
&_OBJC_METACLASS_RO_$_PSYPerson,
};
extern "C" __declspec(dllimport) struct _class_t OBJC_CLASS_$_NSObject;
// 类部分
extern "C" __declspec(dllexport) struct _class_t OBJC_CLASS_$_PSYPerson __attribute__ ((used, section ("__DATA,__objc_data"))) = {
0, // &OBJC_METACLASS_$_PSYPerson,
0, // &OBJC_CLASS_$_NSObject,
0, // (void *)&_objc_empty_cache,
0, // unused, was (void *)&_objc_empty_vtable,
&_OBJC_CLASS_RO_$_PSYPerson,
};
__declspec(allocate(".objc_inithooks$B")) static void *OBJC_CLASS_SETUP[] = {
(void *)&OBJC_CLASS_SETUP_$_PSYPerson,
};
其定义如下,可以看到:
元类PSYPerson的isa = 元类NSObject
元类PSYPerson的superclass = 元类NSObject
类PSYPerson的isa = 元类PSYPerson
类PSYPerson的superclass = 类NSObject
static void OBJC_CLASS_SETUP_$_PSYPerson(void ) {
OBJC_METACLASS_$_PSYPerson.isa = &OBJC_METACLASS_$_NSObject;
OBJC_METACLASS_$_PSYPerson.superclass = &OBJC_METACLASS_$_NSObject;
OBJC_METACLASS_$_PSYPerson.cache = &_objc_empty_cache;
OBJC_CLASS_$_PSYPerson.isa = &OBJC_METACLASS_$_PSYPerson;
OBJC_CLASS_$_PSYPerson.superclass = &OBJC_CLASS_$_NSObject;
OBJC_CLASS_$_PSYPerson.cache = &_objc_empty_cache;
}
类关系图中虚线是isa指针指向流程,实线部分是superclass指针指向流程;类的实例对象(PSYPerson的实例)的isa指向类(PSYPerson类)eg: 线1
,类(PSYPerson)的superclass指向它的父类一直到NSObject eg: 线4、线5
(NSObject的父类是nil eg:线线6
),类(PSYPerson)的isa指向元类(Meta PSYPerson),eg : 线11
,元类的superclass指向父元类 eg: 线7
,元类的isa指向根元类(Meta NSObject) eg:线12
,根元类(Meta NSObject)的isa指向根元类自己(Meta NSObject)eg:线34
,根元类(Meta NSObject)的父类是根类,也就是NSObject eg:线35
。
为了验证上图的关系,首先看一下类方法+ (Class)class
和实例方法- (Class)class
的源码实现,如下:
+ (Class)class { // class类方法,直接返回类本身
return self;
}
- (Class)class { // class实例方法,则会获取对象的isa方法
return object_getClass(self);
}
Class object_getClass(id obj)
{
if (obj) return obj->getIsa();
else return Nil;
}
情景:object 是 NSObject的实例,结合运行时几个函数:object_getClass
获取isa,class_getSuperclass
获取superclass,class_isMetaClass判断一个类是否是元类对象。
- 线3可通过
object_getClass(object)
验证 - 线6可通过
class_getSuperclass([object class])
验证 - 线35可通过
class_getSuperclass(object_getClass(NSObject.class))
或者class_getSuperclass(object_getClass(object_getClass(object)))
验证 - 线34可通过
object_getClass(object_getClass(NSObject.class))
或者object_getClass (object_getClass(object_getClass(object)))
验证
来看类OBJC_CLASS_$_PSYPerson
中有一个_OBJC_CLASS_RO_$_PSYPerson
,RO(read only)是一个只读属性,在编译时期就确定的。再看一下它的结构体值如下:
static struct _class_ro_t _OBJC_CLASS_RO_$_PSYPerson __attribute__ ((used, section ("__DATA,__objc_const"))) = {
0, __OFFSETOFIVAR__(struct PSYPerson, _isWorking), sizeof(struct PSYPerson_IMPL),
0,
"PSYPerson",
(const struct _method_list_t *)&_OBJC_$_INSTANCE_METHODS_PSYPerson,
0,
(const struct _ivar_list_t *)&_OBJC_$_INSTANCE_VARIABLES_PSYPerson,
0,
(const struct _prop_list_t *)&_OBJC_$_PROP_LIST_PSYPerson,
};
存在MachO的__DATA,__objc_const
的section
段,其定义如下:
struct _class_ro_t {
unsigned int flags;
unsigned int instanceStart;
unsigned int instanceSize;
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;
const unsigned char *weakIvarLayout;
const struct _prop_list_t *properties;
};
对应的在这个read only的_class_ro_t结构体中,有_method_list_t
结构体类型的基方法列表baseMethods
1、实例方法列表
static struct /*_method_list_t*/ {
unsigned int entsize; // sizeof(struct _objc_method)
unsigned int method_count; // 方法个数
struct _objc_method method_list[9];
} _OBJC_$_INSTANCE_METHODS_PSYPerson __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_objc_method),
9,
{{(struct objc_selector *)"run", "v16@0:8", (void *)_I_PSYPerson_run},
{(struct objc_selector *)"name", "@16@0:8", (void *)_I_PSYPerson_name},
{(struct objc_selector *)"setName:", "v24@0:8@16", (void *)_I_PSYPerson_setName_},
{(struct objc_selector *)"age", "q16@0:8", (void *)_I_PSYPerson_age},
{(struct objc_selector *)"setAge:", "v24@0:8q16", (void *)_I_PSYPerson_setAge_},
{(struct objc_selector *)"nickName", "@16@0:8", (void *)_I_PSYPerson_nickName},
{(struct objc_selector *)"setNickName:", "v24@0:8@16", (void *)_I_PSYPerson_setNickName_},
{(struct objc_selector *)"isWorking", "B16@0:8", (void *)_I_PSYPerson_isWorking},
{(struct objc_selector *)"setIsWorking:", "v20@0:8B16", (void *)_I_PSYPerson_setIsWorking_}}
};
_objc_method的定义如下
struct _objc_method {
struct objc_selector * _cmd;
const char *method_type;
void *_imp;
};
2、类方法列表
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_PSYPerson __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_objc_method),
1,
{{(struct objc_selector *)"run", "v16@0:8", (void *)_C_PSYPerson_run}}
};
有_objc_protocol_list
结构体类型的基协议列表baseProtocols
struct protocol_list_t {
// count is 64-bit by accident.
unsigned int protocol_count;
struct _protocol_t protocol_list[0]; // variable-size
}
协议结构体的声明如下:
struct _protocol_t {
void * isa; // NULL
const char *protocol_name;
const struct _protocol_list_t * protocol_list; // super protocols
const struct method_list_t *instance_methods;
const struct method_list_t *class_methods;
const struct method_list_t *optionalInstanceMethods;
const struct method_list_t *optionalClassMethods;
const struct _prop_list_t * properties;
const unsigned int size; // sizeof(struct _protocol_t)
const unsigned int flags; // = 0
const char ** extendedMethodTypes;
};
有_ivar_list_t
结构体类型的成员变量列表ivars
static struct /*_ivar_list_t*/ {
unsigned int entsize; // sizeof(struct _prop_t)
unsigned int count;
struct _ivar_t ivar_list[4];
} _OBJC_$_INSTANCE_VARIABLES_PSYPerson __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_ivar_t),
4,
{{(unsigned long int *)&OBJC_IVAR_$_PSYPerson$_isWorking, "_isWorking", "B", 0, 1},
{(unsigned long int *)&OBJC_IVAR_$_PSYPerson$_name, "_name", "@\"NSString\"", 3, 8},
{(unsigned long int *)&OBJC_IVAR_$_PSYPerson$_age, "_age", "q", 3, 8},
{(unsigned long int *)&OBJC_IVAR_$_PSYPerson$_nickName, "_nickName", "@\"NSString\"", 3, 8}}
};
成员变量结构体_ivar_t的声明如下:
struct _ivar_t {
unsigned long int *offset; // pointer to ivar offset location
const char *name;
const char *type;
unsigned int alignment;
unsigned int size;
};
有_prop_list_t
结构体类型的属性列表properties
static struct /*_prop_list_t*/ {
unsigned int entsize; // sizeof(struct _prop_t)
unsigned int count_of_properties;
struct _prop_t prop_list[4];
} _OBJC_$_PROP_LIST_PSYPerson __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_prop_t),
4,
{{"name","T@\"NSString\",C,N,V_name"},
{"age","Tq,N,V_age"},
{"nickName","T@\"NSString\",C,N,V_nickName"},
{"isWorking","TB,N,V_isWorking"}}
};
属性_prop_t的声明如下:
struct _prop_t {
const char *name;
const char *attributes;
};
感兴趣的读者可以结合MachO
可执行文件通过MachOView
查看探索,你会得到一个更加清晰的见解。
小结
- 实例对象的本质是结构体
- 类对象以及元类对象的本质都是结构体
- 从main.cpp分析可得到类的结构图
二、objc源码分析
本文是基于objc4-756.2分析(因为穷Mac硬件只支持到这个版本)
顺着源码一步一步分析可以得到objc_object结构体
struct objc_object { // objc.h
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
struct objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
......
......
......
};
struct class_rw_t {
// Be warned that Symbolication knows the layout of this structure.
uint32_t flags;
uint32_t version;
const class_ro_t *ro;
method_array_t methods;
property_array_t properties;
protocol_array_t protocols;
Class firstSubclass;
Class nextSiblingClass;
char *demangledName;
#if SUPPORT_INDEXED_ISA
uint32_t index;
#endif
};
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
#ifdef __LP64__
uint32_t reserved;
#endif
const uint8_t * ivarLayout;
const char * name;
method_list_t * baseMethodList;
protocol_list_t * baseProtocols;
const ivar_list_t * ivars;
const uint8_t * weakIvarLayout;
property_list_t *baseProperties;
.....
.....
};
总结
- 对象的本质是结构体
- class_rw_t是运行时产生的,支持动态添加方法、属性、类等
- 所有的对象(实例,类,元类)都存在isa
- 实例的isa是类
- 类的isa是元类
- 元类的isa是Meta NSObject
- Meta NSObject的isa是自己(Meta NSObject)
- NSObject的父类是nil
- Meta NSObject的父类是NSObject
最后使用一张图总结: