OC底層原理學習筆記(一) - OC對象的本質(zhì)

一、OC的本質(zhì)

我們平時編寫的Objective-C代碼,底層實現(xiàn)其實都是C\C++代碼
所以O(shè)bjective-C的面向?qū)ο蠖际腔贑\C++的數(shù)據(jù)結(jié)構(gòu)實現(xiàn)的
Objective-C的對象、類主要是基于C\C++的結(jié)構(gòu)體實現(xiàn)的

如何將Objective-C代碼轉(zhuǎn)換為C\C++代碼?
在終端輸入:xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc OC源文件 -o 輸出的cpp文件
例如:xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp

二、一個NSObject對象占用多少內(nèi)存?

系統(tǒng)分配了16個字節(jié)給NSObject對象(通過malloc_size函數(shù)獲得系統(tǒng)實際分配的內(nèi)存大小)
但NSObject對象內(nèi)部只使用了8個字節(jié)的空間(64位環(huán)境下,可以通過class_getInstanceSize函數(shù)獲得)

NSObject *obj = [[NSObject alloc] init];
// 獲得NSObject實例對象的成員變量所占用的大?。?
NSLog(@"%zd", class_getInstanceSize([NSObject class]));
// 獲得obj指針所指向內(nèi)存的大小:16
NSLog(@"%zd", malloc_Size((__bridge const void *)obj));

// C++代碼,內(nèi)部只有一個成員變量isa指針,所以只占用8字節(jié)
struct NSObject_IMPL {
    Class isa;
};

// runtime底層源碼,size最小為16
size_t instanceSize(size_t extraBytes) {
    size_t size = alignedInstanceSize() + extraBytes;
    // CF requires all objects be at least 16 bytes.
   if (size < 16) size = 16;
   return size;
}

三、一個Person對象、一個Student對象占用多少內(nèi)存空間?

@interface Person : NSObject {
    int _age;
}

@interface Student : Person {
    int _no;
}

// C++代碼
struct NSObject_IMPL {
    Class isa;
};

struct Person_IMPL {
    struct NSObject_IMPL NSObject_IVARS; // 8
    int _age; // 4
}; // 16 內(nèi)存對齊:結(jié)構(gòu)體的大小必須是最大成員大小的倍數(shù)

struct Student_IMPL {
    struct Person_IMPL Person_IVARS; // 16,有4個字節(jié)是空的正好給_no使用
    int _no; // 4
}; // 16

// runtime底層源碼,size最小為16
size_t instanceSize(size_t extraBytes) {
    size_t size = alignedInstanceSize() + extraBytes;
    // CF requires all objects be at least 16 bytes.
   if (size < 16) size = 16;
   return size;
}

1、一個Person對象占用16個字節(jié):isa占用8個字節(jié),_age占用4個字節(jié),8 + 4 < 16,所以取16
2、一個Student對象占用16個字節(jié):isa占用8個字節(jié),父類的_age占用4個字節(jié),_no占用4個字節(jié),8 + 4 + 4 = 16字節(jié)
3、內(nèi)存對齊
計算結(jié)構(gòu)體的大小的內(nèi)存對齊:結(jié)構(gòu)體的大小必須是最大成員大小的倍數(shù)
系統(tǒng)分配內(nèi)存的內(nèi)存對齊方式:16的倍數(shù)

四、OC對象

OC對象有instance對象(實例對象)、class對象(類對象)、meta-class對象(元類對象),class對象、meta-class對象的本質(zhì)結(jié)構(gòu)都是struct objc_class

//instance對象(實例對象)
NSObject *object1 = [[NSObject alloc] init];
NSObject *object2 = [[NSObject alloc] init];
//class對象(類對象)
//class方法返回的一直是class對象(類對象)
Class objectClass1 = [object1 class];
Class objectClass2 = [object2 class];
Class objectClass3 = object_getClass(object1);
Class objectClass4 = object_getClass(object2);
Class objectClass5 = [NSObject class];
//meta-class對象(元類對象)
//將類對象當做參數(shù)傳入,獲得元類對象
Class metaClass = object_getClass(objectClass5);
NSLog(@"metaClass - %p", metaClass);

1、instance對象(實例對象)

instance對象就是通過類alloc出來的對象,每次調(diào)用alloc都會產(chǎn)生新的instance對象
instance對象在內(nèi)存中存儲的信息包括:
(1)isa指針
(2)其他成員變量

2、class對象(類對象)

每個類在內(nèi)存中有且只有一個class對象
類對象在內(nèi)存中存儲的信息主要包括:
(1)isa指針
(2)superclass指針
(3)類的屬性信息(@property)、類的對象方法信息(instance method)
(4)類的協(xié)議信息(protocol)、類的成員變量信息(ivar)

3、meta-class對象(元類對象)

每個類在內(nèi)存中有且只有一個meta-class對象
meta-class對象和class對象的內(nèi)存結(jié)構(gòu)是一樣的,但是用途不一樣
在內(nèi)存中存儲的信息主要包括:
(1)isa指針
(2)superclass指針
(3)類的類方法信息(class method)

五、從源碼查看struct objc_class結(jié)構(gòu)

struct objc_class {
    Class isa;
    Class superclass;
    cache_t cache;             // 方法緩存
    class_data_bits_t bits;    // 用于獲取具體的類信息
};

// bits & FAST_DATA_MASK
struct class_rw_t {
    uint32_t flags;
    uint32_t version;
    const class_ro_t *ro;
    method_list_t * methods;    // 方法列表
    property_list_t *properties;    // 屬性列表
    const protocol_list_t * protocols;  // 協(xié)議列表
    Class firstSubclass;
    Class nextSiblingClass;
    char *demangledName;
};

struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;  // instance對象占用的內(nèi)存空間
#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;
};

六、對象的isa指針和superclass指針指向哪里?

image.png

1、isa指針
instance對象的isa指針指向class對象
class對象的isa指針指向meta-class對象
meta-class對象的isa指針指向基類的meta-class對象
2、superclass指針
class對象的superclass指針指向父類的class對象
如果沒有父類,superclass指針為nil
meta-class對象的superclass指針指向父類的meta-class對象
基類的meta-class的superclass指針指向基類的class對象

蘋果源碼:opensource.apple.com/tarballs
objc4源碼下載:https://opensource.apple.com/tarballs/objc4/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容