前言
我們都知道對(duì)象由類(lèi)實(shí)例化而來(lái),在上一篇《OC底層系列二》-對(duì)象中恨诱,我們知道對(duì)象是一個(gè)objc_object類(lèi)型的結(jié)構(gòu)體斩萌,類(lèi)是一個(gè)objc_class類(lèi)型的結(jié)構(gòu)體抹沪,今天我們從底層來(lái)探究對(duì)象和類(lèi)是如何建立關(guān)聯(lián)纵菌。
目錄
0、簡(jiǎn)介
- 本文主要探索OC對(duì)象和類(lèi)之間如何建立關(guān)聯(lián)玄柠,并進(jìn)行驗(yàn)證突梦。
1、對(duì)象和類(lèi)的定義
- 我們?cè)購(gòu)脑创a角度看看對(duì)象和類(lèi)的定義
typedef struct objc_class *Class; // 類(lèi)的定義
typedef struct objc_object *id; // 對(duì)象的定義
1.1随闪、objc_object
// objc-private.h
// objc_object 的實(shí)現(xiàn)
struct objc_object {
private:
isa_t isa;
以下是一些函數(shù)阳似,省略
...
}
1.2、objc_class
// objc-runtime-new.h
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的部分方法代碼省略不貼出來(lái)
}
- 從源碼中我們看到objc_class繼承自objc_object铐伴,說(shuō)明了類(lèi)也是一個(gè)對(duì)象撮奏, objc_class繼承自objc_object,自然也就繼承了objc_object的成員当宴,則objc_class也擁有一個(gè)isa畜吊,由此我們推斷對(duì)象和類(lèi)的關(guān)聯(lián)在于isa。
2户矢、isa
// objc-private.h
// isa_t的定義玲献,一個(gè)聯(lián)合體,值為cls或者bits
union isa_t {
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
Class cls;
uintptr_t bits;
#if defined(ISA_BITFIELD)
struct {
ISA_BITFIELD; // defined in isa.h
};
#endif
};
2.1梯浪、isa的初始化
- objc_object中初始化isa方法源碼如下捌年,如下:
// objc_private.h
struct objc_object {
private:
isa_t isa;
public:
···
private:
void initIsa(Class newCls, bool nonpointer, bool hasCxxDtor);
···
}
// objc-object.h
inline void
objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor)
{
assert(!isTaggedPointer());
if (!nonpointer) {
// 2.1.1
isa.cls = cls;
} else {
// 2.1.2
assert(!DisableNonpointerIsa);
assert(!cls->instancesRequireRawIsa());
isa_t newisa(0);
#if SUPPORT_INDEXED_ISA
// 2.1.3
assert(cls->classArrayIndex() > 0);
newisa.bits = ISA_INDEX_MAGIC_VALUE;
// isa.magic is part of ISA_MAGIC_VALUE
// isa.nonpointer is part of ISA_MAGIC_VALUE
newisa.has_cxx_dtor = hasCxxDtor;
newisa.indexcls = (uintptr_t)cls->classArrayIndex();
#else
// 2.1.4
newisa.bits = ISA_MAGIC_VALUE;
// isa.magic is part of ISA_MAGIC_VALUE
// isa.nonpointer is part of ISA_MAGIC_VALUE
newisa.has_cxx_dtor = hasCxxDtor;
newisa.shiftcls = (uintptr_t)cls >> 3;
#endif
// This write must be performed in a single store in some cases
// (for example when realizing a class because other threads
// may simultaneously try to use the class).
// fixme use atomics here to guarantee single-store and to
// guarantee memory order w.r.t. the class index table
// ...but not too atomic because we don't want to hurt instantiation
isa = newisa;
}
}
- 通常我們創(chuàng)建的OC對(duì)象都是nonpointer,所以會(huì)執(zhí)行2.1.2,創(chuàng)建一個(gè)isa_t類(lèi)型的newisa并初始化其成員bits為0挂洛。
- SUPPORT_INDEXED_ISA定義如下礼预,根據(jù)注釋?zhuān)浔硎?isa_t 中存放的 Class 表示的是否為Class 的地址,是一個(gè)索引(根據(jù)該索引可在類(lèi)信息表中查找該類(lèi)結(jié)構(gòu)地址)虏劲。
// objc-config.h
// Define SUPPORT_INDEXED_ISA=1 on platforms that store the class in the isa
// field as an index into a class table.
// Note, keep this in sync with any .s files which also define it.
// Be sure to edit objc-abi.h as well.
#if __ARM_ARCH_7K__ >= 2 || (__arm64__ && !__LP64__)
# define SUPPORT_INDEXED_ISA 1
#else
# define SUPPORT_INDEXED_ISA 0
#endif
- 我們來(lái)分析一下SUPPORT_INDEXED_ISA宏定義的值托酸,__ARM_ARCH_7K__,從名稱(chēng)上看其表示在 ARM 7k 架構(gòu) CPU 的代碼中的標(biāo)志宏柒巫,我們可以在LLVM 開(kāi)源的ARM.cpp找到其定義:
// ARM.cpp
// Unfortunately, __ARM_ARCH_7K__ is now more of an ABI descriptor. The CPU
// happens to be Cortex-A7 though, so it should still get __ARM_ARCH_7A__.
if (getTriple().isWatchABI())
Builder.defineMacro("__ARM_ARCH_7K__", "2");
通過(guò)注釋和代碼可以知道励堡,這個(gè)值只有在iWatch下才會(huì)被定為2,換句話說(shuō)__ARM_ARCH_7K__代表的是iWatch的宏堡掏。由此可知应结,在iPhone模擬器以及真機(jī)上__ARM_ARCH_7K__值為FALSE。
__arm64__表示是否采用arm64架構(gòu)泉唁。在模擬器上為FALSE摊趾,真機(jī)上為TRUE币狠。
__LP64__ 表示在64位機(jī)器上,如果int是32位砾层,long是64位,pointer也是64位贱案,那么該機(jī)器就是__LP64__肛炮。在模擬器上和真機(jī)上__LP64__為TRUE。
綜上宝踪,ARM_ARCH_7K >= 2 || (arm64 && !LP64)
=FALSE || FALSE
=FALSE
所以SUPPORT_INDEXED_ISA的值為FALSE侨糟。因此初始化isa方法走的是2.1.4
// 2.1.4
newisa.bits = ISA_MAGIC_VALUE;
// isa.magic is part of ISA_MAGIC_VALUE
// isa.nonpointer is part of ISA_MAGIC_VALUE
newisa.has_cxx_dtor = hasCxxDtor;
newisa.shiftcls = (uintptr_t)cls >> 3;
2.2、shiftcls
shiftcls的值是isa中cls的值右移三位得到瘩燥,shiftcls存儲(chǔ)類(lèi)指針的值秕重。根據(jù)shiftcls的宏定義,在 x86_64 架構(gòu)有 44位 用來(lái)存儲(chǔ)類(lèi)指針厉膀,arm64 架構(gòu)中有 33位 溶耘。
-
我們?cè)趚86_64(模擬器下)為研究,ISA_BITFIELD定義如下:
image.png shiftcls的值為二進(jìn)制的3~46位服鹅。
我們通過(guò)LLDB驗(yàn)證shitfcls是否存儲(chǔ)著cls信息,添加如下代碼并在NSLog處添加斷點(diǎn):
#import <Foundation/Foundation.h>
// Animal繼承NSObject凳兵,沒(méi)有添加任何成員
#import "Animal.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
Animal *animal = [Animal alloc];
NSLog(@"Hello, World!");
}
return 0;
}
-
在控制臺(tái)使用LLDB如下操作:
image.png - x/4gx 打印對(duì)象anmial的內(nèi)存信息,以16進(jìn)制格式打印4個(gè)8字節(jié)企软。其第一個(gè)8字節(jié)為isa庐扫。
- p/t animal 將[animal class]的值以二進(jìn)制格式輸出。
格式化二進(jìn)制如下:
// [animal class]
$0 = 0b 0000 0000 0000 0000 00 00 0000 0000 0001 0000 0000 0000 0000 0010 0000 1111 0 000
// isa
$2 = 0b 0000 0000 0001 1101 10 00 0000 0000 0001 0000 0000 0000 0000 0010 0000 1111 0 001
- 對(duì)上面打印結(jié)果格式化可以看到仗哨,[animal class]的3~46位和isa的3~46位位是一樣的形庭,驗(yàn)證了對(duì)象的關(guān)于類(lèi)的信息是存在在isa中的shiftcls中。
3厌漂、[object class]方法分析
- [animal class]中class的底層實(shí)現(xiàn):
\\ objc-object.h
inline Class
objc_object::ISA()
{
ASSERT(!isTaggedPointer());
#if SUPPORT_INDEXED_ISA
// 3.1
if (isa.nonpointer) {
uintptr_t slot = isa.indexcls;
return classForIndex((unsigned)slot);
}
return (Class)isa.bits;
#else
// 3.2
return (Class)(isa.bits & ISA_MASK);
#endif
}
- SUPPORT_INDEXED_ISA值為FALSE萨醒,所以走//3.2,返回(Class)(isa.bits & ISA_MASK);
// isa.h
define ISA_MASK 0x00007ffffffffff8ULL
4桩卵、通過(guò)LLDB驗(yàn)證對(duì)象和類(lèi)如何關(guān)聯(lián)
-
我們根據(jù)isa.bits & ISA_MASK使用LLDB進(jìn)行驗(yàn)證验靡,繼續(xù)如下操作
image.png $3即ISA_MASK的二進(jìn)制表示,$6即(isa.bits &ISA_MASK)的結(jié)果雏节,最后我們d打印$6的描述為Animal,驗(yàn)證完畢胜嗓。
5、總結(jié)
- 對(duì)象的類(lèi)信息存儲(chǔ)在其isa中的的shiftcls中钩乍,對(duì)象和類(lèi)的通過(guò)對(duì)象中的ias的shiftcls進(jìn)行關(guān)聯(lián)辞州,class方法本質(zhì)上返回的是isa的shiftcls,其底層實(shí)現(xiàn)通過(guò)isa.bit& ISA_MASK獲取到shiftcls的值寥粹。
- 我們可以理解為類(lèi)實(shí)例化的對(duì)象的isa指向該類(lèi)变过。
6埃元、TODO
- OC對(duì)象的isa(其位域成員shiftcls)中的存著類(lèi)的信息,OC類(lèi)也是一個(gè)對(duì)象媚狰,那么OC類(lèi)的isa(其位域成員shiftcls)存儲(chǔ)著什么呢岛杀?
- 源碼中objc-class有一個(gè)superclass,我們可以推測(cè)superclass代表當(dāng)前類(lèi)的父類(lèi)崭孤,Animal的superclass應(yīng)該為NSObject類(lèi)类嗤,那么NSObjec類(lèi)的superclass是什么?
- 這些我會(huì)在下一篇文章中繼續(xù)探究辨宠。