作者:GDCoder
鏈接:https://juejin.cn/post/6946507569535909919
前言:最近應(yīng)該有很多小伙伴去跳槽面試的吧,相信各位有的已經(jīng)順利收到offer了助泽,而有些則是碰壁了找筝,那么我在這里給大家準(zhǔn)備了相關(guān)面試資料岖是,還有相關(guān)算法資料纺腊。想了解的可找我拿
首先我們先來看一下這道面試題是啥?
題目看著非常簡單,我是先創(chuàng)建了一個(gè)繼承NSObject的GDPerson類;
GDPerson類的.h文件
GDPerson類的.m文件
再看一下我們viewController.m里面的代碼:
這是題目
請(qǐng)問:
1.print能不能調(diào)用成功?如果不能會(huì)怎么樣?如果能的話調(diào)用結(jié)果是什么?
這個(gè)又是一個(gè)更扯的面試題,真正開發(fā)的時(shí)候,誰也不會(huì)這么寫,這個(gè)還是主要考你基礎(chǔ)!相信你看到這個(gè)題目之后應(yīng)該心中已經(jīng)有了答案,要不知道結(jié)果,要么可能知道結(jié)果,要么猶豫不決,要么不知道哈哈!
其實(shí)這個(gè)面試題考點(diǎn)比較多,考點(diǎn)如下:
1.你要了解super的本質(zhì),第一個(gè)參數(shù)要傳結(jié)構(gòu)體
2.函數(shù)的堆棧分配問題
3.消息機(jī)制,調(diào)用方法是怎么調(diào)用
4.訪問成員變量的本質(zhì)
這樣,我們先來看一下調(diào)用結(jié)果吧!
請(qǐng)看結(jié)果:
面試題運(yùn)用結(jié)果
這里跟你想的答案一樣嗎?
這樣我在cls前面加一段代碼,我們?cè)倏匆幌陆Y(jié)果:
作為一個(gè)開發(fā)者利职,有一個(gè)學(xué)習(xí)的氛圍跟一個(gè)交流圈子特別重要滔灶,這是一個(gè)我的iOS交流圈子:[891 488 181] 送膳,不管你是小白還是大牛歡迎入駐 员魏,分享BAT,阿里面試題、面試經(jīng)驗(yàn)叠聋,討論技術(shù)撕阎, 大家一起交流學(xué)習(xí)成長!
面試題運(yùn)用結(jié)果
首先我們立刻會(huì)有2個(gè)疑問:
1.為什么能調(diào)用成功?
2.為什么self.name調(diào)用結(jié)果是viewController?
一.為什么能調(diào)用成功?
[(__bridge id)obj print];由之前的學(xué)習(xí),我們知道這個(gè)代碼的本質(zhì)是:給obj發(fā)一條print的消息,就會(huì)去通過obj的isa找到obj的類對(duì)象,去找方法列表,這個(gè)是非常清楚的.這個(gè)能調(diào)用成功,說明(__bridge id)obj也存在我們之前說的是isa指針這個(gè)東西
我畫個(gè)圖,這樣理解的比較清楚.
cls是指向GDPerson,obj是指向cls,所以圖如下:
上面綠色是[GDPerson class],圖比較模糊
再請(qǐng)看下面的代碼:
person指向GDPerson的實(shí)例變量,而GDPerson的實(shí)例變量是包括isa和成員變量等等,這個(gè)也很清楚.而isa是指向GDPerson的類對(duì)象,所以請(qǐng)看下面的圖:
我們根據(jù)之前的源碼分析知道,isa和_name是存在一個(gè)結(jié)構(gòu)體,而對(duì)于結(jié)構(gòu)體來說,第一個(gè)成員變量的地址值就是這個(gè)結(jié)構(gòu)體的地址.所以person就是指向isa.
好了,這兩個(gè)圖我們分析清楚了以后,你看這兩個(gè)圖是不是很類似,幾乎是一樣的,我們?cè)倏聪旅娴囊粋€(gè)圖:
上面綠色是[GDPerson class],圖比較模糊
所以從上面的結(jié)構(gòu)上,你看是不是就是一樣的,obj就相當(dāng)于person,所以能調(diào)用,這個(gè)比較抽象.說白了,你上面寫的cls就是isa作用,因?yàn)槲覀冎乐赶蝾悓?duì)象的指針就是isa.isa就是存儲(chǔ)類對(duì)象的地址值.而你可能有疑問cls里面都沒有_name怎么能算是GDPerson對(duì)象呢?注意,我們是調(diào)用print方法,調(diào)用方法沒有說一定有_name成員變量!是這樣吧!它是跟有沒有成員變量是沒有關(guān)系的.
第二個(gè)角度解釋:obj怎么找到cls,就是通過cls對(duì)象的前8個(gè)字節(jié)的內(nèi)存地址找到它,前8個(gè)字節(jié)也是結(jié)構(gòu)體的地址,通過地址就能很容易找到class對(duì)象,是這樣的.所以它能夠調(diào)用成功!這就是調(diào)用的本質(zhì),后面那條線的調(diào)用也是如此.
二.為什么self.name調(diào)用結(jié)果是其他的?
首先你要知道堆棧排列的知識(shí)點(diǎn),請(qǐng)看下圖:
這些變量都是存在椔挡梗空間的,而且內(nèi)存地址是由高地址到底地址.
好我們?cè)倏聪旅孢@個(gè)之前的圖:
我們畫一下這些地址排列如下
上面代碼的結(jié)構(gòu)示意圖
上面綠色是[GDPerson class],圖比較模糊,這個(gè)圖很清楚.
現(xiàn)在我們來回憶一下:之前我們定義一個(gè)對(duì)象,比如上面的GDPerson這個(gè)類,它的底層生成的結(jié)構(gòu)是下面這個(gè)樣子的
structGDPerson_IMPL
{
Class isa;
NSString *_name;
}
上面這個(gè)結(jié)構(gòu)體就是底層的結(jié)構(gòu),現(xiàn)在我們想一下,怎么找到_name這個(gè)地址,肯定是找到isa指針的地址加上8個(gè)字節(jié)就能找到_name吧?看下圖
這個(gè)應(yīng)該是很明顯,找name就是通過isa找到name對(duì)應(yīng)的這塊內(nèi)存地址就行了.
現(xiàn)在大家知道下結(jié)果了吧?上面的cls就是我們的isa指針,所以找name就找到了test這里面!好我們?cè)龠\(yùn)行一下看看
這里你定義test,你定義任何其他的都是一樣,都會(huì)找到cls前面聲明的變量.比如我再定義一個(gè)objct再看下.
輸出的結(jié)果就是cls上面最近的一個(gè)創(chuàng)建的.還有一個(gè)未解決就是self.name調(diào)用結(jié)果是viewController
三虏束、為什么self.name調(diào)用結(jié)果是viewController?
我們把test變量去掉,結(jié)果就會(huì)是viewController 我直接說了這個(gè)主要是[super viewDidLoad]影響;從上一張博客我們知道
super做了什么事它底層是這樣實(shí)現(xiàn)的(上個(gè)博客說得很清楚): objc_msgSendSuper({ self,[UIViewController Class]} ,@selector(viewDidLoad));其他就是做了這件事@selector(viewDidLoad)也可以寫出sel_registerName("viewDidLoad")
這個(gè)肯定要開始定義一個(gè)局部的結(jié)構(gòu)體才能傳入 objc_msgSendSuper這個(gè)方法.所以最高地址是abc這個(gè)結(jié)構(gòu)體,而結(jié)構(gòu)體的第一個(gè)參數(shù)的地址就是結(jié)構(gòu)體的地址,所以輸出的就是self也就是viewController.
如下圖:
就會(huì)找到self
下面我們通過內(nèi)存來證明一下這個(gè)東西:
這個(gè)題目涉及的知識(shí)點(diǎn)還是比較多,如果直接給你題目憑空想想,還是很難想出答案,好了,就說這么多了
文章到這里就結(jié)束了棉饶,你也可以私信我及時(shí)獲取最新資料以及面試相關(guān)資料。如果你有什么意見和建議歡迎給我留言镇匀。