作為iOS開發(fā),這道面試題你能答出來,說明你基礎(chǔ)很OK!

首先我們先來看一下這道面試題是啥?


題目看著非常簡單,我是先創(chuàng)建了一個繼承NSObject的GDPerson類;

GDPerson類的.h文件

GDPerson類的.m文件

再看一下我們viewController.m里面的代碼:

作為一個開發(fā)者,有一個學習的氛圍跟一個交流圈子特別重要,這是一個我的iOS開發(fā)交流群:130 595 548,不管你是小白還是大牛都歡迎入駐 ,讓我們一起進步,共同發(fā)展?。ㄈ簝?nèi)會免費提供一些群主收藏的免費學習書籍資料以及整理好的幾百道面試題和答案文檔?。?/p>

這是題目

請問:

1.print能不能調(diào)用成功?如果不能會怎么樣?如果能的話調(diào)用結(jié)果是什么?

這個又是一個更扯的面試題,真正開發(fā)的時候,誰也不會這么寫,這個還是主要考你基礎(chǔ)!相信你看到這個題目之后應該心中已經(jīng)有了答案,要不知道結(jié)果,要么可能知道結(jié)果,要么猶豫不決,要么不知道哈哈!

其實這個面試題考點比較多,考點如下:

1.你要了解super的本質(zhì),第一個參數(shù)要傳結(jié)構(gòu)體

2.函數(shù)的堆棧分配問題

3.消息機制,調(diào)用方法是怎么調(diào)用

4.訪問成員變量的本質(zhì)

這樣,我們先來看一下調(diào)用結(jié)果吧!

請看結(jié)果:

面試題運用結(jié)果

這里跟你想的答案一樣嗎?

這樣我在cls前面加一段代碼,我們再看一下結(jié)果:

面試題運用結(jié)果

首先我們立刻會有2個疑問:

1.為什么能調(diào)用成功?

2.為什么self.name調(diào)用結(jié)果是viewController?

一.為什么能調(diào)用成功?

[(__bridge id)obj print];由之前的學習,我們知道這個代碼的本質(zhì)是:給obj發(fā)一條print的消息,就會去通過obj的isa找到obj的類對象,去找方法列表,這個是非常清楚的.這個能調(diào)用成功,說明(__bridge id)obj也存在我們之前說的是isa指針這個東西

我畫個圖,這樣理解的比較清楚.

cls是指向GDPerson,obj是指向cls,所以圖如下:

上面綠色是[GDPerson class],圖比較模糊

再請看下面的代碼:

person指向GDPerson的實例變量,而GDPerson的實例變量是包括isa和成員變量等等,這個也很清楚.而isa是指向GDPerson的類對象,所以請看下面的圖:

我們根據(jù)之前的源碼分析知道,isa和_name是存在一個結(jié)構(gòu)體,而對于結(jié)構(gòu)體來說,第一個成員變量的地址值就是這個結(jié)構(gòu)體的地址.所以person就是指向isa.

好了,這兩個圖我們分析清楚了以后,你看這兩個圖是不是很類似,幾乎是一樣的,我們再看下面的一個圖:

上面綠色是[GDPerson class],圖比較模糊

所以從上面的結(jié)構(gòu)上,你看是不是就是一樣的,obj就相當于person,所以能調(diào)用,這個比較抽象.說白了,你上面寫的cls就是isa作用,因為我們知道指向類對象的指針就是isa.isa就是存儲類對象的地址值.而你可能有疑問cls里面都沒有_name怎么能算是GDPerson對象呢?注意,我們是調(diào)用print方法,調(diào)用方法沒有說一定有_name成員變量!是這樣吧!它是跟有沒有成員變量是沒有關(guān)系的.

第二個角度解釋:obj怎么找到cls,就是通過cls對象的前8個字節(jié)的內(nèi)存地址找到它,前8個字節(jié)也是結(jié)構(gòu)體的地址,通過地址就能很容易找到class對象,是這樣的.所以它能夠調(diào)用成功!這就是調(diào)用的本質(zhì),后面那條線的調(diào)用也是如此.

二.為什么self.name調(diào)用結(jié)果是其他的?

首先你要知道堆棧排列的知識點,請看下圖:

這些變量都是存在棧空間的,而且內(nèi)存地址是由高地址到底地址.

好我們再看下面這個之前的圖:

我們畫一下這些地址排列如下

上面代碼的結(jié)構(gòu)示意圖

上面綠色是[GDPerson class],圖比較模糊,這個圖很清楚.

現(xiàn)在我們來回憶一下:之前我們定義一個對象,比如上面的GDPerson這個類,它的底層生成的結(jié)構(gòu)是下面這個樣子的

structGDPerson_IMPL

{

Class isa;

NSString *_name;

}

上面這個結(jié)構(gòu)體就是底層的結(jié)構(gòu),現(xiàn)在我們想一下,怎么找到_name這個地址,肯定是找到isa指針的地址加上8個字節(jié)就能找到_name吧?看下圖

這個應該是很明顯,找name就是通過isa找到name對應的這塊內(nèi)存地址就行了.

現(xiàn)在大家知道下結(jié)果了吧?上面的cls就是我們的isa指針,所以找name就找到了test這里面!好我們再運行一下看看

這里你定義test,你定義任何其他的都是一樣,都會找到cls前面聲明的變量.比如我再定義一個objct再看下.

輸出的結(jié)果就是cls上面最近的一個創(chuàng)建的.還有一個未解決就是self.name調(diào)用結(jié)果是viewController

三、為什么self.name調(diào)用結(jié)果是viewController?

我們把test變量去掉,結(jié)果就會是viewController 我直接說了這個主要是[super viewDidLoad]影響;從上一張博客我們知道

super做了什么事它底層是這樣實現(xiàn)的(上個博客說得很清楚): objc_msgSendSuper({ self,[UIViewController Class]} ,@selector(viewDidLoad));其他就是做了這件事@selector(viewDidLoad)也可以寫出sel_registerName("viewDidLoad")

這個肯定要開始定義一個局部的結(jié)構(gòu)體才能傳入 objc_msgSendSuper這個方法.所以最高地址是abc這個結(jié)構(gòu)體,而結(jié)構(gòu)體的第一個參數(shù)的地址就是結(jié)構(gòu)體的地址,所以輸出的就是self也就是viewController.

如下圖:

就會找到self

下面我們通過內(nèi)存來證明一下這個東西:

這個題目涉及的知識點還是比較多,如果直接給你題目憑空想想,還是很難想出答案,好了,就說這么多了

如果覺得我寫得對您有所幫助,請點贊關(guān)注,我會持續(xù)更新??

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

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

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