前言: 学习了OC之后,我们知道类和方法的定义和使用,为了更好理解类和方法,这里我将初步解析iOS类与方法底层实现方式。
首先我们建一个测试类MyTestClass
类文件
测试代码如下:
#import
@interface MyTestClass : NSObject
@property NSString *myTestProperty;
@property (nonatomic, copy) NSString *mySecondProperty;
@end
#import "MyTestClass.h"
@implementation MyTestClass
- (void)myTestMethod {
NSLog(@"myTestMethod");
}
+ (void)myClassMethod {
NSLog(@"myClassMethod");
}
然后在终端使用命令xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc MyTestClass.m
,就会将对应iOS代码
转成了C++
代码.对应文件下就会生成对应的MyTestClass.cpp
文件。
现在我们就开始分析这个C++
文件:
我们来到MyTestClass.cpp
文件最后,可以看到:
static struct _class_t *L_OBJC_LABEL_CLASS_$ [1] __attribute__((used, section ("__DATA, __objc_classlist,regular,no_dead_strip")))= {
&OBJC_CLASS_$_MyTestClass,
};
上面代码是将定义的类写到___DATA
,__objc_classlist
这个section
中。
在从MyTestClass.cpp
文件向上看看对类的初始化方法:
//_declspec(dllimport) 是说这个函数是从别的DLL导入。我要用。
//_declspec(dllexport) 是说这个函数要从本DLL导出。我要给别人用。
extern "C" __declspec(dllimport) struct _class_t OBJC_METACLASS_$_NSObject;
extern "C" __declspec(dllexport) struct _class_t OBJC_CLASS_$_MyTestClass __attribute__ ((used, section ("__DATA,__objc_data"))) = {
0, // &OBJC_METACLASS_$_MyTestClass,
0, // &OBJC_CLASS_$_NSObject,
0, // (void *)&_objc_empty_cache,
0, // unused, was (void *)&_objc_empty_vtable,
&_OBJC_CLASS_RO_$_MyTestClass,
};
extern "C" __declspec(dllimport) struct _class_t OBJC_CLASS_$_NSObject;
extern "C" __declspec(dllexport) struct _class_t OBJC_CLASS_$_MyTestClass __attribute__ ((used, section ("__DATA,__objc_data"))) = {
0, // &OBJC_METACLASS_$_MyTestClass,
0, // &OBJC_CLASS_$_NSObject,
0, // (void *)&_objc_empty_cache,
0, // unused, was (void *)&_objc_empty_vtable,
&_OBJC_CLASS_RO_$_MyTestClass,
};
static void OBJC_CLASS_SETUP_$_MyTestClass(void ) {
OBJC_METACLASS_$_MyTestClass.isa = &OBJC_METACLASS_$_NSObject;
OBJC_METACLASS_$_MyTestClass.superclass = &OBJC_METACLASS_$_NSObject;
OBJC_METACLASS_$_MyTestClass.cache = &_objc_empty_cache;
OBJC_CLASS_$_MyTestClass.isa = &OBJC_METACLASS_$_MyTestClass;
OBJC_CLASS_$_MyTestClass.superclass = &OBJC_CLASS_$_NSObject;
OBJC_CLASS_$_MyTestClass.cache = &_objc_empty_cache;
}
从上面我们可以看出OBJC_CLASS_$_MyTestClass
是一个_class_t
结构。
在MyTestClass.cpp
文件中我们可以找到该结构体的定义:
struct _class_t {
struct _class_t *isa;
struct _class_t *superclass;
void *cache;
void *vtable;
struct _class_ro_t *ro;
};
从上面的方法static void OBJC_CLASS_SETUP_$_MyTestClass
中可以看到:
1:MyTestClass
类的isa
指向MyTestClass
的metaClass
(元类)。
MyTestClass
的superclass
是NSObject
.
而MyTestClass
的metaClass
的isa
则指向父类NSObject
的metaClass
.
根据继承关系,我们可以得到类的关系指向图。这里我们用网上流传很广的一张图:
其中图中实线表示
superClass
指针,虚线表示
isa
指针。
从图中我们可以看出:
1.类实例的isa
指向它的class
。类的superClass
指向父类,类的isa
指向meta-class
(元类)。而元类的isa
则指向父类的meta-class
.
2.直到根元类NSObject
的isa
指向自己。而他的superClass
则是nill
.
从MyTestClass.cpp
文件中我们再找到OBJC_CLASS_$_MyTestClass
的相关定义:
extern "C" __declspec(dllexport) struct _class_t OBJC_CLASS_$_MyTestClass __attribute__ ((used, section ("__DATA,__objc_data"))) = {
0, // &OBJC_METACLASS_$_MyTestClass,
0, // &OBJC_CLASS_$_NSObject,
0, // (void *)&_objc_empty_cache,
0, // unused, was (void *)&_objc_empty_vtable,
&_OBJC_CLASS_RO_$_MyTestClass,
};
然后再找到_OBJC_CLASS_RO_$_MyTestClass
此变量的定义:
static struct _class_ro_t _OBJC_CLASS_RO_$_MyTestClass __attribute__ ((used, section ("__DATA,__objc_const"))) = {
0, __OFFSETOFIVAR__(struct MyTestClass, _myTestProperty), sizeof(struct MyTestClass_IMPL),
0,
"MyTestClass",
(const struct _method_list_t *)&_OBJC_$_INSTANCE_METHODS_MyTestClass,
0,
(const struct _ivar_list_t *)&_OBJC_$_INSTANCE_VARIABLES_MyTestClass,
0,
(const struct _prop_list_t *)&_OBJC_$_PROP_LIST_MyTestClass,
};
从MyTestClass.cpp
文件中再找到_class_ro_t
结构体的定义
struct _class_ro_t {
unsigned int flags;//标记
unsigned int instanceStart;//实例初始化大小
unsigned int instanceSize;//实例的大小
const unsigned char *ivarLayout;//记录了哪些是 strong 的 ivar
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;//记录了哪些是 weak 的 ivar
const struct _prop_list_t *properties;//@property属性列表
};
_class_ro_t
该结构体其实就是objc_class
结构体的变形,代表根类的结构体类型。 我们可以在官方公开的runtime源码文件runtime.h,找到objc_class
定义:
typedef struct objc_class *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;
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;
从上面我们也可以看出isa指针是和Class同类型的objc_class结构指针。
我们再从MyTestClass.cpp
文件中找到_class_ro_t
中_INSTANCE_METHODS_MyTestClass
实例方法的定义:
struct _objc_method {
struct objc_selector * _cmd;
const char *method_type;
void *_imp;
};
static struct /*_method_list_t*/ {
unsigned int entsize; // sizeof(struct _objc_method)
unsigned int method_count;
struct _objc_method method_list[5];
} _OBJC_$_INSTANCE_METHODS_MyTestClass __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_objc_method),
5,
{{(struct objc_selector *)"myTestMethod", "v16@0:8", (void *)_I_MyTestClass_myTestMethod},
{(struct objc_selector *)"myTestProperty", "@16@0:8", (void *)_I_MyTestClass_myTestProperty},
{(struct objc_selector *)"setMyTestProperty:", "v24@0:8@16", (void *)_I_MyTestClass_setMyTestProperty_},
{(struct objc_selector *)"mySecondProperty", "@16@0:8", (void *)_I_MyTestClass_mySecondProperty},
{(struct objc_selector *)"setMySecondProperty:", "v24@0:8@16", (void *)_I_MyTestClass_setMySecondProperty_}}
};
从上面可以看出定义了实例方法的个数和每个方法。方法的定义中包含了方法名,方法签名和方法的实现。其中_myTestMethod
的_I_MyTestClass_myTestMethod
方法具体实现如下:
static void _I_MyTestClass_myTestMethod(MyTestClass * self, SEL _cmd) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_nq_7n_dy67x0x13zxzr8d8p9bd00000gn_T_MyTestClass_69c7f3_mi_0);
}
而类方法我们要在meta-class(元类)中找。我们从MyTestClass.cpp
中找到对应类方法的定义:
static struct _class_ro_t _OBJC_METACLASS_RO_$_MyTestClass __attribute__ ((used, section ("__DATA,__objc_const"))) = {
1, sizeof(struct _class_t), sizeof(struct _class_t),
0,
"MyTestClass",
(const struct _method_list_t *)&_OBJC_$_CLASS_METHODS_MyTestClass,
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_MyTestClass __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_objc_method),
1,
{{(struct objc_selector *)"myClassMethod", "v16@0:8", (void *)_C_MyTestClass_myClassMethod}}
};
类对象既然称为对象,那它也是一个实例。类对象中也有一个isa
指针指向它的元类(meta class),即类对象是元类的实例。元类内部存放的是类方法列表,根元类的isa指针指向自己,superclass
指针指向NSObject
类。
最后我们再看下myTestClass
的定义:
struct NSObject_IMPL {
Class isa;
};
struct MyTestClass_IMPL {
struct NSObject_IMPL NSObject_IVARS;
NSString *_myTestProperty;
NSString *_mySecondProperty;
};
小结:我们只是通过一个测试类MyTestClass
类文件的C++
源码来简单分析了一下其类与方法的实现。
想了解更多可参考:
Objective-C Class Ivar Layout 探索
iOS开发·runtime原理与实践: 基本知识篇(类,超类,元类,super_class,isa,对象,方法,SEL,IMP)