iOS类与方法底层实现初探

前言: 学习了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指向MyTestClassmetaClass(元类)。
MyTestClasssuperclassNSObject.
MyTestClassmetaClassisa则指向父类NSObjectmetaClass.
根据继承关系,我们可以得到类的关系指向图。这里我们用网上流传很广的一张图:

iOS类与方法底层实现初探_第1张图片
类关系图

其中图中实线表示 superClass指针,虚线表示 isa指针。

从图中我们可以看出:
1.类实例的isa指向它的class。类的superClass指向父类,类的isa指向meta-class(元类)。而元类的isa则指向父类的meta-class.
2.直到根元类NSObjectisa指向自己。而他的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)

你可能感兴趣的:(iOS类与方法底层实现初探)