《iOS之一起進(jìn)大廠》系列-美團(tuán)面試問到分類Category底層原理知識,今天分享出來

學(xué)而時習(xí)之,不亦說乎

前面的話

原諒我池充,我是個標(biāo)題黨,所有文章的名字只是我的噱頭缎讼,偉大的喬布斯告訴我們"Stay hungry,Stay foolish"收夸,希望大家有空杯心態(tài) ,一起學(xué)習(xí)血崭,一起進(jìn)步卧惜。

分類Category 我想絕大部分人應(yīng)該不陌生厘灼,就算自己沒寫過分類Category ,一些知名的三方庫里都會用到咽瓷。 而且這也是各一線大廠面試出現(xiàn)頻率很高的題 设凹。

上一篇文章,有人反饋說茅姜,文章提到的問題闪朱,是最基礎(chǔ)的。意思是還要深挖钻洒?更多深底層奋姿? 我知道人的精力是有限的,每個人準(zhǔn)備面試時間也是有限的素标,在有限的時間里胀蛮,最大限度的提高復(fù)習(xí)效率,這才是正道糯钙。 我也盡量在文中體現(xiàn)適當(dāng)?shù)脑矸嗬牵创a細(xì)節(jié)。

不禁感慨想起一句話: 面試造火箭任岸,入職擰螺絲再榄。 不過小白們也不要憤憤不平。 畢竟好崗位競爭激烈享潜,只有面試造火箭才能找出出更優(yōu)秀人困鸥。不然大家都考100分,那怎么區(qū)分出誰更厲害剑按。

開始面試

我正在會議室略有緊張的等待面試疾就,忽然看到一個穿著格子襯衫,大腹便便的中年男子拿著簡歷向我走來艺蝴, 我看著他頭上快要絕頂?shù)念^發(fā)猬腰,心想這肯定是個iOS開發(fā)技術(shù)牛逼閃閃的老前輩。
還好看過《iOS之面試總結(jié)》系列猜敢,想想現(xiàn)在是滿腹經(jīng)綸姑荷,剛緊張到提到嗓子眼的心,又按下去了缩擂,淡定從容鼠冕,一點(diǎn)都不虛好伐,就是這么自信淡定胯盯。

我什么時候也能變成那樣厲害的高手

變強(qiáng)了

小伙子懈费,你家里里提到用過Category,那你可以說他的使用場景是什么博脑,用途是什么憎乙?

帥氣逼人的面試官您好薄坏,Category的用戶可以歸納為以下幾點(diǎn):

  1. 給現(xiàn)有類添加方法,豐富現(xiàn)有類的功能寨闹。 比如有的人就為NSString這類添加了一些很實用的方法(判斷字符串是否郵箱胶坠,轉(zhuǎn)化字符串為MD5)
  2. 分解代碼龐大功能復(fù)雜的類。把功能復(fù)雜代碼很多的類繁堡,可以按照不同功能的做分類沈善,同一功能放到一個文件里,體現(xiàn)單一職責(zé)原則椭蹄。
  3. 聲明私有方法闻牡。比如定義一個分類,只有頭文件放到對應(yīng)宿主.m里绳矩,滿足私有方法的聲明和使用罩润,不暴露具體實現(xiàn)。

還有其他用法翼馆, 但是蘋果不歡迎這樣用法: 把系統(tǒng)Framework的私有方法公開化割以。

那你說說Category的底層實現(xiàn)是什么?

熟悉oc底層的同學(xué)知道应媚,在runtime層都是類和對象都是 struct表示的严沥,category也不例外,category用結(jié)構(gòu)體category_t中姜,結(jié)構(gòu)體包含:

  1. 類的名字(name)
  2. 類(cls)
  3. category中所有給類添加的實例方法的列表(instanceMethods)
  4. category中所有添加的類方法的列表(classMethods)
  5. category實現(xiàn)的所有協(xié)議的列表(protocols)
  6. category中添加的所有屬性(instanceProperties)
typedef struct category_t {
    const char *name;
    classref_t cls;
    struct method_list_t *instanceMethods;
    struct method_list_t *classMethods;
    struct protocol_list_t *protocols;
    struct property_list_t *instanceProperties;
} category_t;

從category的定義也可以看出category的可為(可以添加實例方法消玄,類方法,甚至可以實現(xiàn)協(xié)議丢胚,添加屬性)翩瓜。
category成員變量列表是只讀,所以category不能添加實例變量携龟。

小伙子不錯兔跌,那你再說說 Category的特點(diǎn)有什么?和 Class Extendsion(類擴(kuò)展)有什么區(qū)別骨宠?

帥氣的面試官浮定,這個不難。 我先說下特點(diǎn)层亿。

  • 分類的特點(diǎn)

分類是運(yùn)行時決議。怎么理解運(yùn)行時決議呢? 編譯好的分類的文件立美,是沒把相應(yīng)分類的內(nèi)容加到宿主類上的匿又。只有在運(yùn)行時Runtime 才把分類的內(nèi)容添加到宿主類上。

  • 類擴(kuò)展的用途是什么建蹄?

一般把不想對外公開一些類的方法碌更,屬性裕偿,成員變量的時候可以用類的擴(kuò)展
類擴(kuò)展代碼格式:

@interface XXX ()
//私有屬性
//私有方法(如果不實現(xiàn),編譯時會報警,Method definition for 'XXX' not found)
@end

  • 分類和類擴(kuò)展的區(qū)別是痛单?
  1. 擴(kuò)展是編譯時決議嘿棘。 分類是運(yùn)行時決議
  2. 分類有聲明和實現(xiàn)。擴(kuò)展只以聲明的形式存在旭绒,多數(shù)情況下寄生于宿主類的.m中鸟妙。
  3. 系統(tǒng)類可以添加分類,但是不能為系統(tǒng)類添加擴(kuò)展挥吵。

那咱們再聊深一點(diǎn)的重父,Category中+load 和+initialize調(diào)用的順序是什么樣的? Category的+load 和+initialize 方法的區(qū)別什么忽匈?

  • 調(diào)用順序:
  1. 類要優(yōu)先于分類調(diào)用+load方法房午。
  2. 先編譯的分類的+load方法會被優(yōu)先調(diào)。
  3. 父類+load優(yōu)先于子類丹允。
  4. 由于分類是objc_msgSend機(jī)制郭厌,+initialize在所有分類要優(yōu)先于類調(diào)用。 在類中 +initialize父類優(yōu)先于子類 雕蔽。如果子類沒有實現(xiàn)+initialize沪曙,會調(diào)用父類的+initialize(所以同一個父類的+initialize可能會被調(diào)用多次)。

是什么決定了哪個先編譯呢萎羔?如下圖Category1的+load比Category2的+load優(yōu)先調(diào)用液走。如果編譯文件順序換一下,被調(diào)用的順序也跟著變贾陷。

  • +load 和+initialize 區(qū)別在于調(diào)用方式和調(diào)用時刻不同
  1. 調(diào)用方式不同:
    +load是根據(jù)函數(shù)地址直接調(diào)用缘眶,initialize是通過objc_msgSend調(diào)用

  2. 調(diào)用時刻不同:
    +load方法會在runtime加載類、分類時調(diào)用(而且程序運(yùn)行過程中只調(diào)用一次)髓废。
    +initialize是類第一次接收到消息的時候調(diào)用(即是類調(diào)用alloc時)巷懈,每一個類只會initialize一次(上面提到子類沒有實現(xiàn)+initialize,會調(diào)用父類的+initialize慌洪。這樣父類的initialize方法可能會被調(diào)用多次)

那怎么理解category方法覆蓋的問題顶燕?

分類添加的方法可以“覆蓋”原類方法

其實覆蓋沒有真正的覆蓋。如果在category里添加了methodA冈爹,那么原類的methodA也是存在的涌攻,沒有真正覆蓋掉。只是系統(tǒng)只會調(diào)用后來category添加的 methodA频伤。

因為category的methodA被放到了方法列表的前面恳谎,原來類中methodA被放到了方法列表的后面,在運(yùn)行時查找方法會先找到了category 添加的同名方法,就產(chǎn)生了“覆蓋“原來類的同名方法的效果因痛。

如果多個分類有同名方法婚苹,那么誰能生效取決于誰最后參與編譯。最后參與編譯的分類對應(yīng)的方法就會生效鸵膏。

能否給category添加實例變量膊升?那如何給分類添加實例變量?

不能谭企。
從上面提到的分類的底層實現(xiàn)廓译,category成員變量列表是只讀,所以category不能添加實例變量赞咙。

那怎么添加呢责循? 直接添加肯定是不行,可以間接的添加.

  1. 思路1
    給分類添加全局變量攀操,并且手動重寫setter/getter方法實現(xiàn)院仿。但是全局變量有很多隱患,對象銷毀時無法銷毀速和。不建議采用歹垫。

  2. 思路2
    用關(guān)聯(lián)對象方法添加實例變量。
    通過runtime提供的關(guān)聯(lián)對象的方法可以簡潔的給分類添加成員變量颠放。
    通過下面提供的關(guān)聯(lián)對象下API排惨,可以實現(xiàn)給分類添加實例變量:

添加關(guān)聯(lián)對象
void objc_setAssociatedObject(id object, const void * key, id value, objc_AssociationPolicy policy)
獲得關(guān)聯(lián)對象
id objc_getAssociatedObject(id object, const void * key)
移除所有的關(guān)聯(lián)對象
void objc_removeAssociatedObjects(id object)

簡單說下關(guān)聯(lián)對象方法添加實例變量原理:

其實關(guān)聯(lián)對象并沒有添加到實例變量到被關(guān)聯(lián)對象內(nèi)存中,
關(guān)聯(lián)對象有一個全局內(nèi)容管理器(AssociationsManager)碰凶,關(guān)聯(lián)對象通過上面提到的三個API暮芭,操作實例變量 存取,移除欲低。從而完成了對分類的添加實例變量辕宏。

面試結(jié)束

小伙子回答的不錯,很對我口味砾莱,記得明天再來瑞筐,明天還有更精彩的面試其他內(nèi)容。 我的內(nèi)心OS:天吶嚕腊瑟,明天還有>奂佟! 這是要在走禿(走向禿頂?shù)牡缆? 越走越遠(yuǎn)啊闰非。 (為了下一篇文章膘格,強(qiáng)行做引子,哈哈)

堅持看到這里的同學(xué)河胎,你們個個都是人才闯袒,我好喜歡。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末游岳,一起剝皮案震驚了整個濱河市政敢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌胚迫,老刑警劉巖喷户,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異访锻,居然都是意外死亡褪尝,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進(jìn)店門期犬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來河哑,“玉大人,你說我怎么就攤上這事龟虎×Ы鳎” “怎么了?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵鲤妥,是天一觀的道長佳吞。 經(jīng)常有香客問我,道長棉安,這世上最難降的妖魔是什么底扳? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮贡耽,結(jié)果婚禮上衷模,老公的妹妹穿的比我還像新娘。我一直安慰自己蒲赂,他們只是感情好阱冶,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著凳宙,像睡著了一般熙揍。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上氏涩,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天届囚,我揣著相機(jī)與錄音,去河邊找鬼是尖。 笑死意系,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的饺汹。 我是一名探鬼主播蛔添,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了迎瞧?” 一聲冷哼從身側(cè)響起夸溶,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎凶硅,沒想到半個月后缝裁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡足绅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年捷绑,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片氢妈。...
    茶點(diǎn)故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡粹污,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出首量,到底是詐尸還是另有隱情壮吩,我是刑警寧澤,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布蕾总,位于F島的核電站粥航,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏生百。R本人自食惡果不足惜递雀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蚀浆。 院中可真熱鬧缀程,春花似錦、人聲如沸市俊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽摆昧。三九已至撩满,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間绅你,已是汗流浹背伺帘。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留忌锯,地道東北人伪嫁。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像偶垮,于是被迫代替她去往敵國和親张咳。 傳聞我的和親對象是個殘疾皇子帝洪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評論 2 354

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