筆記-OC對(duì)象的本質(zhì)

筆記-OC對(duì)象的本質(zhì)

課堂引入

Q:p1和p2是同一個(gè)對(duì)象嗎稚配?

A:從打印結(jié)果看,顯然p1和p2指向同一塊內(nèi)存地址

Q:同一塊內(nèi)存地址就一定是同一個(gè)對(duì)象嗎姜性?那么給p賦值再看

A:顯然赘风,p1和p2是同一個(gè)對(duì)象。且可以看出init方法并沒(méi)有做什么仁卷,可以直接去掉穴翩,即alloc后p已經(jīng)可以正常使用。那么alloc方法到底做了什么锦积?

A:跳轉(zhuǎn)到alloc的方法看一下芒帕,先去看一下官方文檔中alloc方法的實(shí)現(xiàn)

+ (id)alloc {
    return _objc_rootAlloc(self);
}
//-----------------------------------------------------------

id
_objc_rootAlloc(Class cls)
{
    return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
//-----------------------------------------------------------

static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
#if __OBJC2__
    if (slowpath(checkNil && !cls)) return nil;
    if (fastpath(!cls->ISA()->hasCustomAWZ())) {
        return _objc_rootAllocWithZone(cls, nil);
    }
#endif

    // No shortcuts available.
    if (allocWithZone) {
        return ((id(*)(id, SEL, struct _NSZone *))objc_msgSend)(cls, @selector(allocWithZone:), nil);
    }
    return ((id(*)(id, SEL))objc_msgSend)(cls, @selector(alloc));
}

看下實(shí)際調(diào)用代碼的步驟,先在Person *p = [Person alloc];打個(gè)斷點(diǎn)丰介,跳轉(zhuǎn)到22行objc_alloc

打個(gè)symbolic breakpoint(sb) :alloc看一下alloc中的匯編實(shí)現(xiàn)

利用寄存器打印x0背蟆,確認(rèn)是Person對(duì)象

點(diǎn)擊向下按鈕,進(jìn)入_objc_rootAlloc函數(shù)的匯編里

_objc_rootAlloc中并沒(méi)有看到b跳轉(zhuǎn)到源代碼callAlloc函數(shù)中哮幢,這里是因?yàn)榫幾g器優(yōu)化掉一次函數(shù)調(diào)用带膀,直接使用callAlloc的下級(jí)函數(shù)_objc_rootAllocWithZone的代碼。

使用向下箭頭跳轉(zhuǎn)到ojbc_rootAllocWithZone里橙垢,找到23行ret指令垛叨,跳轉(zhuǎn)到23行

ret指令表示return,此處返回的是個(gè)指針柜某,使用寄存器命令register read x0在lldb中查看x0存儲(chǔ)的參數(shù)嗽元,po打印出來(lái)是Person對(duì)象敛纲,說(shuō)明創(chuàng)建了一個(gè)Person對(duì)象,說(shuō)明alloc才是真正創(chuàng)建實(shí)例對(duì)象的方法还棱,oc對(duì)象本身就是個(gè)結(jié)構(gòu)體指針载慈。

接下來(lái)看看init做了什么?

斷點(diǎn)到init方法珍手,直接看30行objc_msgSend办铡,利用register查看x8,發(fā)現(xiàn)調(diào)用的是init方法

設(shè)置symbolic breakpoint: init斷點(diǎn)琳要,進(jìn)入init寡具,發(fā)現(xiàn)直接ret返回

查看oc源碼,init方法

- (id)init {
    return _objc_rootInit(self);
}

//-----------------------------------------------------------
id
_objc_rootInit(id obj)
{
    // In practice, it will be hard to rely on this function.
    // Many classes do not properly chain -init calls.
    return obj;
}

發(fā)現(xiàn)init確實(shí)沒(méi)做什么直接返回對(duì)象稚补,所以其實(shí)繼承NSObject后alloc就可以使用對(duì)象了童叠。init是留給開(kāi)發(fā)者進(jìn)行重寫(xiě)的方法

拓展知識(shí)點(diǎn)

寄存器的指令跟硬件有關(guān)课幕,5s以后都是ARM64架構(gòu)

64位厦坛? 32位?和CPU有關(guān)-->數(shù)據(jù)吞吐量

一根電線(xiàn) 1個(gè)bit

32根電線(xiàn) 4個(gè)字節(jié)

64根電線(xiàn) 8個(gè)字節(jié)

理論上64位的效率是32位的2倍

真機(jī)debug乍惊,匯編知識(shí)點(diǎn)

  • bl指令:跳轉(zhuǎn)杜秸,調(diào)用函數(shù)
  • 寄存器,在A(yíng)RM64中有32個(gè)润绎,用來(lái)暫存數(shù)據(jù)撬碟。X0-X7存放函數(shù)的參數(shù),如objc_sendMsg(self, SEL)中self存放在X0莉撇,SEL存放在X1呢蛤。lldb調(diào)試中使用register read x1命令查看寄存器x1內(nèi)容
  • b相當(dāng)于bl,ret相當(dāng)于return

編譯器優(yōu)化 棍郎,跳過(guò)bl到下級(jí)函數(shù)其障,直接使用下級(jí)函數(shù)的代碼,優(yōu)化掉函數(shù)調(diào)用涂佃。bl需要訪(fǎng)問(wèn)內(nèi)存静秆,影響效率。編譯器優(yōu)化對(duì)應(yīng)Build Settings中的Optimization Level設(shè)置巡李。

演示Optimization Level設(shè)置

正常debug模式下抚笔,上面QA環(huán)節(jié)中debug模式配置也是如下,w0=1侨拦,w1=2殊橙,調(diào)用sum函數(shù)

w0和w1寄存器比x0和x1寄存器短,是32位的,有4個(gè)字節(jié)32bit位膨蛮,用來(lái)節(jié)約性能叠纹。如傳遞int型,在64位中占用4個(gè)字節(jié)32bit敞葛,需要w寄存器就可以誉察。

修改Debug的編譯器優(yōu)化

發(fā)現(xiàn)匯編代碼量減少,且sum函數(shù)已經(jīng)被優(yōu)化掉了惹谐,直接算出結(jié)果w8=3持偏,這就是編譯器優(yōu)化。

alloc到底是怎么創(chuàng)建對(duì)象的氨肌?鸿秆?

查詢(xún)oc源碼alloc最終實(shí)現(xiàn)在_class_createInstanceFromZone函數(shù)

size算出要初始化對(duì)象的大小,其中extraBytes傳入的是0

說(shuō)明一個(gè)oc對(duì)象最小占用16個(gè)字節(jié)

word_align實(shí)現(xiàn)==>字節(jié)對(duì)齊:內(nèi)存空間按照Byte字節(jié)劃分怎囚,理論上任何數(shù)據(jù)的訪(fǎng)問(wèn)可以從任何的地址值開(kāi)始卿叽,實(shí)際上訪(fǎng)問(wèn)特殊類(lèi)型時(shí)經(jīng)常進(jìn)行空間排列。例如

內(nèi)存地址 數(shù)據(jù)類(lèi)型
001 short
002
003
004
005 int
006 int
007 int
008 int

一個(gè)short數(shù)據(jù)占據(jù)一個(gè)字節(jié)在001恳守,假設(shè)有一個(gè)int數(shù)據(jù)考婴,它在內(nèi)存中占用4個(gè)字節(jié)。因?yàn)橛布?wèn)題催烘,int數(shù)據(jù)并不是緊挨著short類(lèi)型排列在002沥阱,可能是在005。CPU在訪(fǎng)問(wèn)時(shí)颗圣,如果是按照4個(gè)字節(jié)來(lái)訪(fǎng)問(wèn)喳钟,int按照這樣對(duì)齊放置在005-008的話(huà)訪(fǎng)問(wèn)沒(méi)問(wèn)題屁使≡谄瘢可是如果int型放在004-007,CPU先訪(fǎng)問(wèn)001-004獲取部分int數(shù)據(jù)蛮寂,再去訪(fǎng)問(wèn)005-008才能讀取完整的int數(shù)據(jù)蔽午,效率較低,所以采用字節(jié)對(duì)齊酬蹋。字節(jié)對(duì)齊的目的是兼容硬件及老,提高效率,利用空間換時(shí)間。

8字節(jié)對(duì)齊開(kāi)辟空間肯定是8的倍數(shù),如果有個(gè)9個(gè)字節(jié)的數(shù)據(jù)需要16個(gè)字節(jié)空間來(lái)存放锨用。

word_align的實(shí)現(xiàn):8的倍數(shù)的二進(jìn)制低三位都是000乘凸,~按位取反

通過(guò)宏定義可以看出,64位下8字節(jié)對(duì)齊嘿歌,32位下4字節(jié)對(duì)齊

資料

騰訊課堂-iOS底層進(jìn)階-OC對(duì)象的本質(zhì)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末绊困,一起剝皮案震驚了整個(gè)濱河市琼腔,隨后出現(xiàn)的幾起案子寞秃,更是在濱河造成了極大的恐慌斟叼,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件春寿,死亡現(xiàn)場(chǎng)離奇詭異朗涩,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)绑改,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)谢床,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人绢淀,你說(shuō)我怎么就攤上這事萤悴。” “怎么了皆的?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵覆履,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我费薄,道長(zhǎng)硝全,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任楞抡,我火速辦了婚禮伟众,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘召廷。我一直安慰自己凳厢,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布竞慢。 她就那樣靜靜地躺著先紫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪筹煮。 梳的紋絲不亂的頭發(fā)上遮精,一...
    開(kāi)封第一講書(shū)人閱讀 51,443評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音败潦,去河邊找鬼本冲。 笑死,一個(gè)胖子當(dāng)著我的面吹牛劫扒,可吹牛的內(nèi)容都是我干的檬洞。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼沟饥,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼添怔!你這毒婦竟也來(lái)了环戈?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤澎灸,失蹤者是張志新(化名)和其女友劉穎院塞,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體性昭,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拦止,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了糜颠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汹族。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖其兴,靈堂內(nèi)的尸體忽然破棺而出顶瞒,到底是詐尸還是另有隱情,我是刑警寧澤元旬,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布榴徐,位于F島的核電站,受9級(jí)特大地震影響匀归,放射性物質(zhì)發(fā)生泄漏坑资。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一穆端、第九天 我趴在偏房一處隱蔽的房頂上張望袱贮。 院中可真熱鬧,春花似錦体啰、人聲如沸攒巍。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)柒莉。三九已至,卻和暖如春枕屉,著一層夾襖步出監(jiān)牢的瞬間常柄,已是汗流浹背鲤氢。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工搀擂, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人卷玉。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓哨颂,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親相种。 傳聞我的和親對(duì)象是個(gè)殘疾皇子威恼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

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