OC對象的本質(zhì)<二> 實例對象叹话,類對象,元類對象

OC對象的本質(zhì)<一>

OC對象的分類

OC對象可以分為三類墩瞳,分別是實例對象驼壶,類對象,元類對象喉酌。

實例對象(instance對象)

instance對象是通過類alloc出來的對象热凹,每次調(diào)用alloc都會產(chǎn)生新的instance對象。

  • instance對象在內(nèi)存中存儲的信息
    isa指針(因為幾乎所有的對象都繼承自NSObject泪电,而NSObject對象的結(jié)構(gòu)體重就是一個isa指針)
    其他成員變量(注意這里存儲的是成員變量的值)
    我們看一下Demo:
@interface Person:NSObject
{
    @public
    int _age;
}
@property (nonatomic, assign)int height;
@end

@implementation Person
@end

int main(int argc, char * argv[]) {
    @autoreleasepool {
        
        Person *p1 = [[Person alloc] init];
        p1->_age = 3;
        
        Person *p2 = [[Person alloc] init];
        p2->_age = 4;
        
        return 0;
    }
}

那么這個時候首先為p1實例對象分配存儲空間般妙,先存儲isa這個指針,然后存儲成員變量_age=3;對于p2實例對象也是一樣的相速。由于p1指針指向Person實例對象碟渺,也就是指向Person實例對象在內(nèi)存中的首地址,而Person實例對象中存儲的第一個成員變量是isa指針突诬,所以p1指針指向的地址就是存儲isa指針的地址苫拍。


17703D99-4D1C-45D2-85C2-5E053C2FA656.png

類對象(Class對象)

類對象的獲取方式:

NSObject *object1 = [[NSObject alloc] init];
NSObject *object2 = [[NSObject alloc] init];
Class objectClass1 = [object1 class];
Class objectClass2 = [object2 class];
Class objectClass3 = object_getClass(object1);
Class objectClass4 = object_getClass(object2);
Class objectClass5 = [NSObject class];

一個類的類對象在內(nèi)存中是唯一的,這就說明我們通過這五種方式所創(chuàng)建的類方法是同一個對象旺隙。我們通過打印這5個類對象的內(nèi)存地址來驗證一下:

NSLog(@"%p \n %p \n %p \n %p \n %p \n", objectClass1, objectClass2, objectClass3, objectClass4, objectClass5);

打印結(jié)果:

 0x10b0a6ea8 
 0x10b0a6ea8 
 0x10b0a6ea8 
 0x10b0a6ea8 
 0x10b0a6ea8

這也就驗證了這五個對象是同一個對象绒极,也就是一個類只有一個類對象。
既然每個類的類對象只有唯一一個蔬捷,那么在每個類的類對象中會存儲什么東西呢垄提?肯定是存放那么只需要存儲一份的東西,不會是像成員變量的值一樣,每個實例對象都可以有不同的成員變量值塔淤。

  • Class對象在內(nèi)存中存儲的信息主要包括:
    isa指針
    superclass指針
    類的屬性信息(@property)摘昌,類的對象方法信息(instance method)
    類的協(xié)議信息(@protocol)速妖,類的成員變量信息(ivars高蜂,類型,名稱等)


    類對象包含的信息.png

元類對象

  • 元類對象的獲取方法
//我們在object_getClass()方法中傳入類對象就得到了元類對象罕容,每個類的元類對象只有一個备恤,所以objectMetaClass1和objectMetaClass2是同一個對象
 Class objectMetaClass1 = object_getClass([NSObject class]);
 Class objectMetaClass2 = object_getClass(objectClass1);

那么元類對象中存放的是什么信息呢?大家想一下實例對象和元類對象還有什么信息漏了就能明白元類信息中包含什么信息了锦秒。

  • meta-Class對象中包含的信息
    isa指針
    superclass指針
    類的類方法信息


    元類對象包含的信息.png
  • class_isMetaClass()
    class_isMetaClass()判斷傳進(jìn)去的對象是否是元類對象露泊。
    BOOL result = class_isMetaClass(objectMetaClass1);

isa指針

我們先看一個Person類:

@interface Person:NSObject<NSCopying>
{
    @public
    int _age;
}
@property (nonatomic, assign)int no;
- (void)personInstanceMethod;
+ (void)personClassMethod;
@end

@implementation Person
- (void)personInstanceMethod{
    
    
}
+ (void)personClassMethod{
    
    
}

- (id)copyWithZone:(NSZone *)zone{
    
    return nil;
}

這個Person類有成員變量,屬性旅择,有遵守的協(xié)議惭笑,實例方法,類方法生真。首先我們通過實例對象調(diào)用實例方法:

Person *person = [[Person alloc] init];
[person personClassMethod];

[Person personClassMethod]這句代碼在底層的實現(xiàn)一定是objc_msgSend(person,@selector(personInstanceMethod))沉噩。這里就有一個問題了,我們是給實例對象發(fā)消息柱蟀,調(diào)用實例方法川蒙,可以實例對象中沒有實例方法的信息呀。同樣的长已,當(dāng)我們調(diào)用類對象的時候[Person personInstanceMethod]這句話在底層的實現(xiàn)時一定是轉(zhuǎn)化為objc_msgSend([Person class],@selector(personClassMethod))這樣畜眨,也就是給一個類對象發(fā)送消息,調(diào)用類方法术瓮。但是類方法是在元類對象里面康聂,不在類對象中呀,這是怎么調(diào)用的呢胞四?這時isa指針就派上用場了恬汁。
Person實例對象的isa指針指向Person類對象,Person類對象的isa指針指向Person元類對象撬讽。

  • 當(dāng)我們調(diào)用對象方法時蕊连,首先通過實例對象中的isa指針找到類對象,然后獲得類對象中的實例方法信息游昼。
  • 當(dāng)我們調(diào)用類方法時甘苍,首先通過類對象的isa指針找到元類對象,再找到元類對象中的類方法信息烘豌,實現(xiàn)調(diào)用载庭。

superclass指針

類對象的superclass指針

我們創(chuàng)建一個子類Student類繼承自Person類。

@interface Student:Person <NSCoding>
{
    @public
    int _weight;
}
@property (nonatomic, assign)int height;
- (void)studentInstanceMethod;
+ (void)studentClassMethod;

@end

@implementation Student
- (void)studentInstanceMethod{
    
}

+ (void)studentClassMethod{
    
}
- (id)initWithCoder:(NSCoder *)aDecoder{
    
    return nil;
}
- (void)encodeWithCoder:(NSCoder *)aCoder{
    
}
@end
![![85F2CFF1-F8EF-438A-B32D-CF65BCF10A5A.png](https://upload-images.jianshu.io/upload_images/5796542-fdab2d71d7b42f54.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ](https://upload-images.jianshu.io/upload_images/5796542-7e9a426e8fb01d06.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

我們看一下student實例對象調(diào)用實例方法:

Student *student = [[Student alloc] init];
[student studentInstanceMethod];

這個過程我們已經(jīng)很清楚了,就是通過student實例對象的isa指針來找到Student的類對象囚聚,然后在類對象中找到實例方法靖榕,完成調(diào)用。那么如果student實例對象調(diào)用的是父類Person類的實例方法呢顽铸?[student personInstanceMethod];這個調(diào)用過程又是怎樣的呢茁计?- (void)personInstanceMethod這個類方法肯定是存放在Person類的類方法里面的。這個時候就是superclass指針發(fā)揮作用的時候了谓松。
student實例對象首先通過其isa指針找到自己的類對象星压,然后Student類對象查找自己有沒有存儲- (void)personInstanceMethod這個實例方法,發(fā)現(xiàn)自己并沒有這個實例方法的信息鬼譬,于是就通過自己的superclass指針來找到父類的類對象也就是Person類對象娜膘,Person類對象查看自己有沒有存儲- (void)personInstanceMethod這個實例方法的信息,結(jié)果找到了這個實例方法的信息优质,至此student實例對象(^-^)也就獲取了- (void)personInstanceMethod實例方法的信息竣贪。
類對象的superclass指針指向父類的類對象

元類對象的superclass指針

85F2CFF1-F8EF-438A-B32D-CF65BCF10A5A.png

首先我們來看Student類對象調(diào)用自己的類方法:

[Student studentClassMethod];

這個調(diào)用過程應(yīng)該已經(jīng)很清楚了,Student類的類方法信息是存儲在元類對象中的巩螃。Student類對象首先通過自己的isa指針找到Student元類對象演怎,Student元類對象查看自己有沒有studentClassMethod這個類方法的信息,查看后發(fā)現(xiàn)有牺六,就傳給類對象颤枪。那么如果要調(diào)用父類Person類的類方法呢?

[Student personClassMethod];

首先Student類對象通過自己的isa指針找到Student元類對象淑际,Student元類對象查看自己有沒有personClassMethod這個類方法的信息畏纲,查找后沒有就利用自己的superclass指針找到父類的元類對象,也就是Person類的元類對象春缕,Person類的元類對象查看后發(fā)現(xiàn)自己有personClassMethod這個類方法的信息盗胀,至此Student類對象就找到了personClassMethod這個類方法的信息。
元類對象的superclass指針指向父類的元類對象锄贼。

isa,superclass總結(jié)

放上一張經(jīng)典的總結(jié)圖

630FEC40-DF9E-4755-80CA-D65810CB3DF1.png

總結(jié)起來就是:
實例對象的isa指針指向該類的類對象票灰。
類對象的isa指針該類的元類對象。
元類對象的isa指針指向基類的元類對象宅荤。
類對象的superclass指針指向父類的類對象
元類對象的superclass指向父類的元類對象(基類除外)
基類的元類對象的superclass指向基類的類對象屑迂。

isa指針的一個小細(xì)節(jié)

前面已經(jīng)說了實例對象的isa指針指向類對象,類對象的isa指向元類對象惹盼。所以實例對象的isa指針的值就是類對象的地址值,類對象的isa指針的值就是元類對象的地址值惫确。我們打印看一下結(jié)果:

Person *person = [[Person alloc] init];
Class personClass = [Person class];
Class personMetaClass = object_getClass(personClass);
NSLog(@"%p, %p, %p", person, personClass, personMetaClass);

打印結(jié)果:

Student[1372:63404] 0x600000008390, 0x10e7a4130, 0x10e7a4108

然后我們再打個斷點(diǎn)蚯舱,查看一下各個對象的isa指針值兄裂。

1697CA48-0D78-4273-9B39-86D3581DF4DA.png

我們在調(diào)試框中輸入p person->isa發(fā)現(xiàn)打印的是$0 = Person蜈亩,這并不是我們想要的稚配,我們輸入p (long)person->is,這下打印出想要的結(jié)果了$1 = 4537860400港华,但是這是10進(jìn)制表示道川,我們需要轉(zhuǎn)化為16進(jìn)制,再輸入p/x (long)person->isa立宜,打印得到16進(jìn)制結(jié)果:$2 = 0x000000010e7a4130冒萄。這也就驗證了實例對象的isa指針指向類對象。
然后我們試著打印類對象的isa指針的值:
p/x personClass->isa
打印結(jié)果是:
error: member reference base type 'Class' is not a structure or union所以這條路行不通了橙数。
我們已經(jīng)知道了這個personClass這個類對象中第一個成員變量一定是isa指針尊流,所以我們可以自己創(chuàng)建一個結(jié)構(gòu)體:

struct pd_objc_class{
    
    Class isa
};

然后我們把personClass這個類對象強(qiáng)制轉(zhuǎn)化成pd_objc_class結(jié)構(gòu)體類型:

 struct pd_objc_class *personClass2 = (__bridge struct pd_objc_class *)(personClass);

然后再通過p/x personClass2->isa打印isa指針的值:
$0 = 0x000000010583f108,同時我們從一開始的打印結(jié)果可以找到personMetaClass對象的地址為0x000000010583f108灯帮。
這樣也就證明了類對象的isa指針是指向元類對象的崖技。

驗證實例對象,類對象钟哥,元類對象的結(jié)構(gòu)

類對象和元類對象的類型都是Class類型迎献,所以本質(zhì)上來講它們的結(jié)構(gòu)是一致的。那么我們只需要搞清楚這個Class類型的結(jié)構(gòu)就可以搞清楚類對象和元類對象的結(jié)構(gòu)了腻贰。
按住command點(diǎn)擊Class查看結(jié)構(gòu):

typedef struct objc_class *Class;

可以看到這是一個obkc_class類型的結(jié)構(gòu)體指針吁恍。然后我們繼續(xù)點(diǎn)擊進(jìn)objc_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;

但是我們看到這個是條件編譯,#if !OBJC2也就是如果不是OBJC2就編譯播演,但是現(xiàn)在就是OBJC2冀瓦,所以這段條件代碼不會編譯。因此這個代碼就不足以作為參考写烤。那么我們只好從源碼中查看objc_class的結(jié)構(gòu)翼闽。
我們在源碼中搜索objc_class,從objc-runtime-new.h中找到了objc_class的結(jié)構(gòu):

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

    class_rw_t *data() { 
        return bits.data();
    }
}

可以看到顶霞,objc_class這個結(jié)構(gòu)體是繼承自objc_object肄程,我們點(diǎn)進(jìn)objc_object結(jié)構(gòu)體中看看锣吼,可以看到

struct objc_object {
private:
    isa_t isa;
}

里面只有一個成員變量isa指針。所以objc_class這個結(jié)構(gòu)體的結(jié)構(gòu)就等價于:

   struct objc_class : objc_object {
    void *isa;;
    Class superclass;
    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() { 
        return bits.data();
    }
}

第一個成員變量是isa指針蓝厌,第二個是superclass指針玄叠。第三個cache是和方法的緩存有關(guān)的。第四個bits先不管拓提。第五個是一個方法读恃,返回值是class_rw_t類型的,我們點(diǎn)進(jìn)class_rw_t看看它的結(jié)構(gòu):

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;//協(xié)議列表
}

然后我們再點(diǎn)進(jìn)class_ro_t看看它的結(jié)構(gòu):

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;//協(xié)議列表
    const ivar_list_t * ivars;//成員變量列表

    const uint8_t * weakIvarLayout;
    property_list_t *baseProperties;//屬性列表

    method_list_t *baseMethods() const {
        return baseMethodList;
    }
};

從這個角度確實可以證明objc_class的結(jié)構(gòu)中有isa指針代态,superclass指針寺惫,方法列表,屬性列表蹦疑,成員變量列表西雀,協(xié)議列表等。


2874E11F-27F3-4E2B-8276-443CC9CD3A24.png

通過轉(zhuǎn)化為C++的源碼來證實實例對象歉摧,類對象艇肴,元類對象的結(jié)構(gòu)

類對象

@interface Person:NSObject<NSCopying>
{
    @public
    int _age;
}
@property (nonatomic, assign)int no;
- (void)personInstanceMethod;
+ (void)personClassMethod;
@end

@implementation Person
- (void)personInstanceMethod{  
}
+ (void)personClassMethod{   
}
- (id)copyWithZone:(NSZone *)zone{
    return nil;
}

@end

int main(int argc, char * argv[]) {
    @autoreleasepool {
        
        Person *person = [[Person alloc] init];
        person->_age = 10;
        person.no = 3;
        Class personClass = [Person class];
        Class personMetaClass = object_getClass(personClass);
 
        return 0;
    }
}

我們把person類的代碼轉(zhuǎn)為C++的源碼:
我們找到class_t類型的OBJC_CLASS$_Person這個結(jié)構(gòu)體,這個結(jié)構(gòu)體就死類對象的結(jié)構(gòu)叁温。

struct _class_t OBJC_CLASS_$_Person __attribute__ ((used, section ("__DATA,__objc_data"))) = {
    0, // &OBJC_METACLASS_$_Person,
    0, // &OBJC_CLASS_$_NSObject,
    0, // (void *)&_objc_empty_cache,
    0, // unused, was (void *)&_objc_empty_vtable,
    &_OBJC_CLASS_RO_$_Person,

我們找到_class_t這個結(jié)構(gòu)體,查看結(jié)構(gòu)

struct _class_t {
    struct _class_t *isa;
    struct _class_t *superclass;
    void *cache;
    void *vtable;
    struct _class_ro_t *ro;
};

我們看到其中第一個成員是isa指針再悼,第二個成員是superclass指針,cache和vtable我們先不管膝但。接著我們看到_class_ro_t這個結(jié)構(gòu)體:

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;
    const unsigned char *weakIvarLayout;
    const struct _prop_list_t *properties;
};

這個結(jié)構(gòu)體我們前面見多過冲九,應(yīng)該已經(jīng)比較熟悉了。然后我們找到類對象中這個結(jié)構(gòu)的實現(xiàn):

static struct _class_ro_t _OBJC_CLASS_RO_$_Person __attribute__ ((used, section ("__DATA,__objc_const"))) = {
    0, 
    __OFFSETOFIVAR__(struct Person, _age), 
    sizeof(struct Person_IMPL), 
    (unsigned int)0, 
    0, 
    "Person",
    (const struct _method_list_t *)&_OBJC_$_INSTANCE_METHODS_Person,
    (const struct _objc_protocol_list *)&_OBJC_CLASS_PROTOCOLS_$_Person,
    (const struct _ivar_list_t *)&_OBJC_$_INSTANCE_VARIABLES_Person,
    0, 
    (const struct _prop_list_t *)&_OBJC_$_PROP_LIST_Person,
};
  • 我們可以看到instanceSize對應(yīng)的是sizeof(struct Person_IMPL)跟束。
  • name也就是類名莺奸,對應(yīng)的是"Person"。
  • baseMethods對應(yīng)的是OBJC$_INSTANCE_METHODS_Person這個結(jié)構(gòu)體泳炉,我們找到這個結(jié)構(gòu)體的實現(xiàn):
static struct /*_method_list_t*/ {
    unsigned int entsize;  // sizeof(struct _objc_method)
    unsigned int method_count;
    struct _objc_method method_list[4];
} _OBJC_$_INSTANCE_METHODS_Person __attribute__ ((used, section ("__DATA,__objc_const"))) = {
    sizeof(_objc_method),
    4,
    {{(struct objc_selector *)"personInstanceMethod", "v16@0:8", (void *)_I_Person_personInstanceMethod},
    {(struct objc_selector *)"copyWithZone:", "@24@0:8^{_NSZone=}16", (void *)_I_Person_copyWithZone_},
    {(struct objc_selector *)"no", "i16@0:8", (void *)_I_Person_no},
    {(struct objc_selector *)"setNo:", "v20@0:8i16", (void *)_I_Person_setNo_}}
};

我們通過INSTANCE_METHODS這個名字知道這個里面存放的是實例方法憾筏,通過其初始化可以看到,有四個實例方法花鹅,方法名分別是"personInstanceMethod";"copyWithZone:";"no";"setNo:"氧腰。這是符合實際的。

  • baseProtocols根據(jù)名字應(yīng)該是存放的協(xié)議信息刨肃,它是用OBJC_CLASS_PROTOCOLS$_Person這個結(jié)構(gòu)體初始化的古拴。我們找到這個結(jié)構(gòu)體的實現(xiàn):
static struct /*_protocol_list_t*/ {
    long protocol_count;  // Note, this is 32/64 bit
    struct _protocol_t *super_protocols[1];
} _OBJC_CLASS_PROTOCOLS_$_Person __attribute__ ((used, section ("__DATA,__objc_const"))) = {
    1,
    &_OBJC_PROTOCOL_NSCopying
};

可以看到,協(xié)議數(shù)量是1真友,協(xié)議是_OBJC_PROTOCOL_NSCopying黄痪,通過名稱我們得知是NSCopying,這里不再展開盔然。

  • ivars是變量的意思桅打,其對應(yīng)的是OBJC$_INSTANCE_VARIABLES_Person這個結(jié)構(gòu)體是嗜,我們查看一下這個結(jié)構(gòu)體的結(jié)構(gòu):
static struct /*_ivar_list_t*/ {
    unsigned int entsize;  // sizeof(struct _prop_t)
    unsigned int count;
    struct _ivar_t ivar_list[2];
} _OBJC_$_INSTANCE_VARIABLES_Person __attribute__ ((used, section ("__DATA,__objc_const"))) = {
    sizeof(_ivar_t),
    2,
    {{(unsigned long int *)&OBJC_IVAR_$_Person$_age, "_age", "i", 2, 4},
     {(unsigned long int *)&OBJC_IVAR_$_Person$_no, "_no", "i", 2, 4}}
};

可以看到它有兩個成員變量,其中一個是_age,類型是int挺尾,大小是4字節(jié)鹅搪,還有一個成員變量是_no,類型是int遭铺,大小是4字節(jié)丽柿。

  • properties是屬性,可以猜測里面存儲的是屬性信息魂挂。我們看到其對應(yīng)的結(jié)構(gòu)體是_PROP_LIST_Person甫题,查看一下其實現(xiàn):
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_Person __attribute__ ((used, section ("__DATA,__objc_const"))) = {
    sizeof(_prop_t),
    1,
    {{"no","Ti,N,V_no"}}
};

我們可以看到有一個屬性,屬性名是no涂召。

元類對象

我們找到class_t類型的結(jié)構(gòu)體OBJC_METACLASS$_Person坠非,這個結(jié)構(gòu)體就是元類對象的實現(xiàn):

struct _class_t OBJC_METACLASS_$_Person __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_$_Person,

我們找到OBJC_METACLASS_RO$_Person這個結(jié)構(gòu)體

static struct _class_ro_t _OBJC_METACLASS_RO_$_Person __attribute__ ((used, section ("__DATA,__objc_const"))) = {
    1, 
    sizeof(struct _class_t), 
    sizeof(struct _class_t), 
    (unsigned int)0, 
    0, 
    "Person",
    (const struct _method_list_t *)&_OBJC_$_CLASS_METHODS_Person,
    0, 
    0, 
    0, 
    0, 
};

我們通過這個名稱可以看出這是為初始化元類對象的。
還是貼一下_class_ro_t的結(jié)構(gòu):

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;
    const unsigned char *weakIvarLayout;
    const struct _prop_list_t *properties;
};

對比來看芹扭,OBJC_METACLASS_RO_$_Person這個結(jié)構(gòu)體的初始化就要簡單很多麻顶。

  • name就是類名,是"Person"舱卡。
  • baseMethods存放的是方法,其是用OBJC$_CLASS_METHODS_Person這個結(jié)構(gòu)體初始化的队萤,我們查看一下這個結(jié)構(gòu)體的結(jié)構(gòu):
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_Person __attribute__ ((used, section ("__DATA,__objc_const"))) = {
    sizeof(_objc_method),
    1,
    {{(struct objc_selector *)"personClassMethod", "v16@0:8", (void *)_C_Person_personClassMethod}}
};

類方法只有一個轮锥,方法名是“personClassMethod”。
其他的如baseProtocols,ivars,properties這些都是空的要尔。
這也就證實了元類對象中只有isa指針舍杜,superclass指針,還有類方法赵辕。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末既绩,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子还惠,更是在濱河造成了極大的恐慌饲握,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蚕键,死亡現(xiàn)場離奇詭異救欧,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)锣光,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門笆怠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人誊爹,你說我怎么就攤上這事蹬刷∑白剑” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵办成,是天一觀的道長泡态。 經(jīng)常有香客問我,道長诈火,這世上最難降的妖魔是什么兽赁? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮冷守,結(jié)果婚禮上刀崖,老公的妹妹穿的比我還像新娘。我一直安慰自己拍摇,他們只是感情好亮钦,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著充活,像睡著了一般蜂莉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上混卵,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天映穗,我揣著相機(jī)與錄音,去河邊找鬼幕随。 笑死蚁滋,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的赘淮。 我是一名探鬼主播辕录,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼梢卸!你這毒婦竟也來了走诞?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤蛤高,失蹤者是張志新(化名)和其女友劉穎蚣旱,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體襟齿,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡姻锁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了猜欺。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片位隶。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖开皿,靈堂內(nèi)的尸體忽然破棺而出涧黄,到底是詐尸還是另有隱情篮昧,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布笋妥,位于F島的核電站懊昨,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏春宣。R本人自食惡果不足惜酵颁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望月帝。 院中可真熱鬧躏惋,春花似錦、人聲如沸嚷辅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽簸搞。三九已至扁位,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間趁俊,已是汗流浹背域仇。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留寺擂,地道東北人殉簸。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像沽讹,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子武鲁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容