iOS底層-isa結(jié)構(gòu)(isa_t)

iOS 底層-- isa指向探究中探索了isa的指向纤掸,那么isa的結(jié)構(gòu)具體是什么樣的旬陡。從源碼中來(lái)著手研究。

一井辆、位域

在研究isa結(jié)構(gòu)的時(shí)候关筒,需要有位域的相關(guān)只是因?yàn)閕sa的機(jī)構(gòu)是一個(gè)聯(lián)合體+位域的形式


舉個(gè)例子:
坦克大戰(zhàn)的游戲 中 坦克的方向有上下左右的狀態(tài),


常見(jiàn)的寫(xiě)法:為其添加4個(gè)變量杯缺,

@interface JETank : NSObject

@property (nonatomic, assign) BOOL left;
@property (nonatomic, assign) BOOL right;
@property (nonatomic, assign) BOOL top;
@property (nonatomic, assign) BOOL bottom;

@end

這樣可以根據(jù)每個(gè)變量去拿到相應(yīng)的狀態(tài)
但是這里為其分配了多少內(nèi)存蒸播? ------- 8位 (BOOL為1 內(nèi)存對(duì)其 結(jié)果為8)


位域的方式

因?yàn)橛?|1就可以表示具體那個(gè)方向,所以我可以定義聯(lián)合體(union)并且只需要一個(gè)char的長(zhǎng)度就可以表示4個(gè)方向

@interface JETank : NSObject
{
    @public
    union  {
        uintptr_t direction;
        
        struct {
            uintptr_t left   :   1;
            uintptr_t right  :   1;
            uintptr_t top    :   5;  //這里定義為5  只是想說(shuō)  長(zhǎng)度可以根據(jù)不同的需求去自定義
            uintptr_t bottom :   1;
        };
    } _jeTankDirection;
}

這樣只需要對(duì)left/right 等進(jìn)行相應(yīng)的賦值就可以滿(mǎn)足需求

具體賦值方法

JETank *tank = [JETank new];

/**
方法1:
tank->_jeTankDirection.direction = 0x81;
// 或者 tank->_jeTankDirection.direction = 0b0010 0001;
*/

/**
方法二:
*/
tank->_jeTankDirection.left = YES;  // 為什么可以這樣賦值萍肆?  因?yàn)閅ES強(qiáng)轉(zhuǎn)之后為1  二進(jìn)制就是0b1  是滿(mǎn)足的
tank->_jeTankDirection.top = 31;   // 這里如果賦值100會(huì)報(bào)警告(因?yàn)閠op占5位  最大值為 31)
tank->_jeTankDirection.bottom = 0b1;  // 二進(jìn)制方式賦值
    
NSLog(@"left = %@  top = %@  right = %@  bottom = %@",@(tank->_jeTankDirection.left),
          @(tank->_jeTankDirection.top),
          @(tank->_jeTankDirection.right),
          @(tank->_jeTankDirection.bottom));

//打印結(jié)果
left = 1  top = 31  right = 0  bottom = 1

如果top 是賦值 100    100二進(jìn)制為:0b0110 0100  因?yàn)橹徽?為  只取后5位  就是0b00100  最后打印結(jié)果為  top = 8

1袍榆、聯(lián)合體的優(yōu)勢(shì)
聯(lián)合體和結(jié)構(gòu)體寫(xiě)法上有些類(lèi)似,但是注意區(qū)分
聯(lián)合體的所有信息公用一塊內(nèi)存塘揣,起到節(jié)省內(nèi)存的作用
2包雀、位域的作用
直觀的表達(dá)取值范圍,可以直接拿到相應(yīng)的值

二亲铡、isa 結(jié)構(gòu)

我們可以從源碼中找到相關(guān)內(nèi)容:

在底層的代碼中具體為:

inline void 
objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor) 
{ 
    assert(!isTaggedPointer()); 
    ......
}

因?yàn)閭魅氲膎onpointer 為 true 所以這里的代碼可以簡(jiǎn)化為:

inline void 
objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor) 
{ 
        isa_t newisa(0);

        newisa.bits = ISA_MAGIC_VALUE;   // 對(duì)bits進(jìn)行初始化
        newisa.has_cxx_dtor = hasCxxDtor;   //賦值
        newisa.shiftcls = (uintptr_t)cls >> 3; //賦值  與class 進(jìn)行關(guān)聯(lián)

        isa = newisa;
}

在這里進(jìn)行了 isa 的初始化才写。

isa是一個(gè)聯(lián)合體

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

ISA_BITFIELD 在這里是宏定義(根據(jù)架構(gòu)不同葡兑,內(nèi)容不同),可以在進(jìn)去一層查看具體定義
__x86_64__ pc端、 __arm64__ 手機(jī)端64位

這里以arm64為例:

union isa_t {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    Class cls;
    uintptr_t bits;
    struct {
        uintptr_t nonpointer        : 1;
        uintptr_t has_assoc         : 1;
        uintptr_t has_cxx_dtor      : 1; 
        uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ 
        uintptr_t magic             : 6;
        uintptr_t weakly_referenced : 1;
        uintptr_t deallocating      : 1; 
        uintptr_t has_sidetable_rc  : 1;
        uintptr_t extra_rc          : 19
    };
};

對(duì)isa進(jìn)行初始化的時(shí)候赞草,對(duì)bits有一個(gè)默認(rèn)的賦值讹堤,ISA_MAGIC_VALUE 為宏定義,具體為
0x001d800000000001ULL 在系統(tǒng)計(jì)算機(jī)上轉(zhuǎn)換為二進(jìn)制就是64字節(jié)

默認(rèn)值二進(jìn)制

圖解為:
(這張圖來(lái)源網(wǎng)絡(luò) 并稍作改動(dòng)厨疙,是針對(duì) x86_64 結(jié)構(gòu)洲守,于本文稍有出入 ( shiftcls 只到36位為止,后面依次排)

isa_t結(jié)構(gòu)

bits里面的具體信息分別代表什么意思沾凄?

bits是64為字節(jié)  struct是位域

nonpointer :1  (在bits的64位字節(jié)中   第0個(gè)用于nonpointer信息存儲(chǔ))
 表示是否對(duì)isa指針開(kāi)啟指針優(yōu)化岖沛;0代表純isa指針,1代表不止是類(lèi)對(duì)象指針搭独,還包含了類(lèi)信息婴削、對(duì)象的引用計(jì)數(shù)等;

has_assoc:1  (在bits的64位字節(jié)中   第1個(gè)用于has_assoc信息存儲(chǔ))
關(guān)聯(lián)對(duì)象標(biāo)志位牙肝,0沒(méi)有唉俗,1存在

has_cxx_dtor:1  (在bits的64位字節(jié)中   第2個(gè)用于has_cxx_dtor信息存儲(chǔ))
 該對(duì)象是否有C++或者Objc的析構(gòu)器,如果有析構(gòu)函數(shù)配椭,則需要做析構(gòu)邏輯虫溜,如果沒(méi)有,則可以更快的釋放對(duì)象股缸;

shiftcls:33  (在bits的64位字節(jié)中   第3-35用于shiftcls信息存儲(chǔ))
存儲(chǔ)類(lèi)指針的值衡楞。開(kāi)啟指針優(yōu)化的情況下,在arm64架構(gòu)中有33位用來(lái)存儲(chǔ)類(lèi)指針敦姻;

magic:6   (在bits的64位字節(jié)中   第36-41用于magic信息存儲(chǔ))
 用于調(diào)試器判斷當(dāng)前對(duì)象是真的對(duì)象還是沒(méi)有初始化的空間瘾境;

 weakly_referenced :1  (在bits的64位字節(jié)中   第42個(gè)用于weakly_referenced信息存儲(chǔ))
標(biāo)志對(duì)象是否被指向或者曾經(jīng)指向一個(gè)ARC的弱變量,沒(méi)有弱引用的對(duì)象可以更快釋放镰惦;

 deallocating :1
標(biāo)志對(duì)象是否正在釋放內(nèi)存迷守;

 has_sidetable_rc :1
當(dāng)對(duì)象引用計(jì)數(shù)大于10時(shí),則需要借用該變量存儲(chǔ)進(jìn)位

 extra_rc :19
當(dāng)表示該對(duì)象的引用計(jì)數(shù)值旺入,實(shí)際上是引用計(jì)數(shù)值減1兑凿,例如,如果對(duì)象的引用計(jì)數(shù)為10茵瘾,那么extra_rc為9.如果引用計(jì)數(shù)大于10礼华,則需要使用上面提到的has_sidetable_rc。

三拗秘、結(jié)構(gòu)體(struct)與聯(lián)合體(union)

union
1圣絮、可以定義多個(gè)成員,大小由最大的成員的大小決定聘殖。
2晨雳、成員共享同一塊大小的內(nèi)存,一次只能使用其中的一個(gè)成員奸腺。
3餐禁、對(duì)某一個(gè)成員賦值,會(huì)覆蓋其他成員的值(也不奇怪突照,因?yàn)樗麄児蚕硪粔K內(nèi)存帮非。但前提是成員所占字節(jié)數(shù)相同,當(dāng)成員所占字節(jié)數(shù)不同時(shí)只會(huì)覆蓋相應(yīng)字節(jié)上的值讹蘑,比如對(duì)char成員賦值就不會(huì)把整個(gè)int成員覆蓋掉末盔,因?yàn)閏har只占一個(gè)字節(jié),而int占四個(gè)字節(jié))
聯(lián)合體
4座慰、的存放順序是所有成員都從低地址開(kāi)始存放的陨舱。

  • 簡(jiǎn)而言之: union的特點(diǎn):共用一塊內(nèi)存,大小由最長(zhǎng)的那個(gè)成員決定
    對(duì)某一個(gè)成員賦值版仔,會(huì)影響其他成員的值

結(jié)構(gòu)體
本質(zhì)上是多個(gè)變量集合到一起游盲,多個(gè)變量是同時(shí)存在的,互不影響÷福總體的大小是各個(gè)變量值所在內(nèi)存大小的和(由于內(nèi)存對(duì)齊的原則益缎,總體大小總是>=這個(gè)和值)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末然想,一起剝皮案震驚了整個(gè)濱河市莺奔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌变泄,老刑警劉巖令哟,帶你破解...
    沈念sama閱讀 211,348評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異妨蛹,居然都是意外死亡励饵,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)滑燃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)役听,“玉大人,你說(shuō)我怎么就攤上這事表窘〉溆瑁” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,936評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵乐严,是天一觀的道長(zhǎng)瘤袖。 經(jīng)常有香客問(wèn)我,道長(zhǎng)昂验,這世上最難降的妖魔是什么捂敌? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,427評(píng)論 1 283
  • 正文 為了忘掉前任艾扮,我火速辦了婚禮,結(jié)果婚禮上占婉,老公的妹妹穿的比我還像新娘泡嘴。我一直安慰自己,他們只是感情好逆济,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布酌予。 她就那樣靜靜地躺著,像睡著了一般奖慌。 火紅的嫁衣襯著肌膚如雪抛虫。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,785評(píng)論 1 290
  • 那天简僧,我揣著相機(jī)與錄音建椰,去河邊找鬼。 笑死岛马,一個(gè)胖子當(dāng)著我的面吹牛广凸,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蛛枚,決...
    沈念sama閱讀 38,931評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼谅海,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了蹦浦?” 一聲冷哼從身側(cè)響起扭吁,我...
    開(kāi)封第一講書(shū)人閱讀 37,696評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎盲镶,沒(méi)想到半個(gè)月后侥袜,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,141評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡溉贿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評(píng)論 2 327
  • 正文 我和宋清朗相戀三年枫吧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宇色。...
    茶點(diǎn)故事閱讀 38,625評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡九杂,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出宣蠕,到底是詐尸還是另有隱情例隆,我是刑警寧澤,帶...
    沈念sama閱讀 34,291評(píng)論 4 329
  • 正文 年R本政府宣布抢蚀,位于F島的核電站镀层,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏皿曲。R本人自食惡果不足惜唱逢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評(píng)論 3 312
  • 文/蒙蒙 一吴侦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧坞古,春花似錦备韧、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)毅哗。三九已至听怕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間虑绵,已是汗流浹背尿瞭。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留翅睛,地道東北人声搁。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像捕发,于是被迫代替她去往敵國(guó)和親疏旨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評(píng)論 2 348

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