iOS-類(NSObject)的結構

1、NSObject

NSObject爲全部類的根類,它位於整個類層次的根上,類層次中的全部其它類最終都是從根類繼承而來。(萬物皆NSObjectbash

2、類的結構

咱們知道全部的類均可以用class接收,因此咱們建立一個類對象app

Person *person = [Person alloc];
Class pClass     = object_getClass(person);
複製代碼

查看Class源碼:ui

typedef struct objc_class *Class;
複製代碼

查看objc_class源碼:this

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中的Class ISA屬性繼承自父類 objc_object,查看objc_object源碼:atom

struct objc_object {
private:
    isa_t isa;
…
}
複製代碼

???、objc_object與NSObject有什麼關係呢? 咱們再來看NSObject的源碼定義:spa

NSObject的源碼定義:
@interface NSObject <NSObject> {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
    Class isa  OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
}
複製代碼

其實他們是同一個事物的不一樣表現形式。objc_object爲c結構體寫法,而NSObject爲OC寫法。3d

3、類的屬性與方法

咱們爲類對象添加成員變量、屬性和實例方法、類方法:調試

@interface Person : NSObject{
    NSString *hobby;
}
@property (nonatomic, copy) NSString *nickName;
- (void)sayHello;
+ (void)sayHappy;
@end
複製代碼

一、定位源碼

首先咱們查看objc_class源碼中的方法:code

class_rw_t *data() { 
    return bits.data();
}
複製代碼

查看class_rw_t,surprise:orm

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
    …
};

複製代碼

因此咱們要找的東西就在這個class_rw_t裏面。

二、查當作員變量和屬性

接下來咱們開始lldb調試:

咱們須要class_data_bits_t bits的地址:

Class ISA(8個字節)+ Class superclass(8個字節)+ cache_t cache(?)

仍是查看源碼:

typedef uint32_t mask_t; // 4

struct cache_t {
    struct bucket_t *_buckets; // 8
    mask_t _mask;  // 4
    mask_t _occupied; // 4
	…
}
複製代碼

得出: Class ISA(8個字節)+ Class superclass(8個字節)+ cache_t cache(16個字節),即偏移0x20個字節。

查看它的const class_ro_t *ro參數:

2.1 baseProtocols參數

完美找到它的屬性nickName。

2.2 ivars參數

發現ivars裏面同時包含了成員變量hobby,以及帶下劃線的屬性_nickName。

2.3 baseMethodList參數

iOS底層會對屬性自動添加帶下劃線的成員變量以及實現它的getter和setter方法

三、查看實例方法

實例方法一樣存在於baseMethodList中

四、查看類方法

咱們會發現,在class_data_bits_t裏面,是不管如何都找不到類方法的,怎麼辦呢?咱們只能去它的元類裏面查看。定義一個方法:

void testInstanceMethod_classToMetaclass(Class pClass){
    
    const char *className = class_getName(pClass);
    Class metaClass = objc_getMetaClass(className);
    
    Method method1 = class_getInstanceMethod(pClass, @selector(sayHello));
    Method method2 = class_getInstanceMethod(metaClass, @selector(sayHello));
    
    Method method3 = class_getInstanceMethod(pClass, @selector(sayByeBye));
    Method method4 = class_getInstanceMethod(metaClass, @selector(sayByeBye));
    
    NSLog(@"%p-%p-%p-%p",method1,method2,method3,method4);
}

複製代碼

打印結果:

0x100002248-0x0-0x0-0x1000021e0

印證了咱們的想法,類方法確實存在於它的元類裏面。

相關文章
相關標籤/搜索