iOS 分類(Category)知識(shí)點(diǎn)總結(jié)

1.Category是什么捍岳?重寫一個(gè)類的方法用繼承好還是分類好?

? ?Category是類別沉衣;一般情況用分類好郁副,用Category去重寫類的方法,僅對(duì)本Category有效豌习,不會(huì)影響到其他類與原有類的關(guān)系存谎。

category好處:

可以減少單個(gè)文件的體積

可以把不同的功能組織到不同的category里

可以由多個(gè)開發(fā)者共同完成一個(gè)類

可以按需加載想要的category

聲明私有方法

category特點(diǎn)

category只能給某個(gè)已有的類擴(kuò)充方法,不能擴(kuò)充成員變量肥隆。

category中也可以添加屬性既荚,只不過@property只會(huì)生成setter和getter的聲明,不會(huì)生成setter和getter的實(shí)現(xiàn)以及成員變量栋艳。

如果category中的方法和類中原有方法同名恰聘,運(yùn)行時(shí)會(huì)優(yōu)先調(diào)用category中的方法。也就是吸占,category中的方法會(huì)覆蓋掉類中原有的方法晴叨。所以開發(fā)中盡量保證不要讓分類中的方法和原有類中的方法名相同。避免出現(xiàn)這種情況的解決方案是給分類的方法名統(tǒng)一添加前綴矾屯。比如category_兼蕊。

如果多個(gè)category中存在同名的方法,運(yùn)行時(shí)到底調(diào)用哪個(gè)方法由編譯器決定件蚕,最后一個(gè)參與編譯的方法會(huì)被調(diào)用孙技。

2.Category的實(shí)現(xiàn)原理或者本質(zhì) 产禾?

? ?Category編譯之后的底層結(jié)構(gòu)是struct category_t,里面存儲(chǔ)著分類的對(duì)象方法绪杏、類方法下愈、屬性、協(xié)議信息

? ? 在程序運(yùn)行的時(shí)候蕾久,runtime會(huì)將Category的數(shù)據(jù)合并到類信息中(類對(duì)象势似、元類對(duì)象中)

? ? 分類的實(shí)現(xiàn)原理是將category中的方法,屬性僧著,協(xié)議數(shù)據(jù)放在category_t結(jié)構(gòu)體中履因,然后將結(jié)構(gòu)體內(nèi)的方法列表拷貝到類對(duì)象的方法列表中。?

3.Category的加載處理過程是什么盹愚?

? ?通過Runtime加載某個(gè)類的所有Category數(shù)據(jù)

? ? 把所有Category的方法栅迄、屬性、協(xié)議數(shù)據(jù)皆怕,合并到一個(gè)大數(shù)組中

? ? 后面參與編譯的Category數(shù)據(jù)毅舆,會(huì)在數(shù)組的前面

? ? 將合并后的分類數(shù)據(jù)(方法、屬性愈腾、協(xié)議)憋活,插入到類原來數(shù)據(jù)的前面

可以理解為:

? ? 把 category 的實(shí)例方法、協(xié)議以及屬性添加到類上虱黄。

? ? 把 category 的類方法和協(xié)議添加到類的 metaclass 上悦即。

其中需要注意的是:

category 的方法沒有「完全替換掉」原來類已經(jīng)有的方法,也就是說如果 category 和原來類都有 methodA橱乱,那么 category 附加完成之后辜梳,類的方法列表里會(huì)有兩個(gè) methodA。

category 的方法被放到了新方法列表的前面泳叠,而原來類的方法被放到了新方法列表的后面作瞄,這也就是我們平常所說的category 的方法會(huì)「覆蓋」掉原來類的同名方法,這是因?yàn)檫\(yùn)行時(shí)在查找方法的時(shí)候是順著方法列表的順序查找的析二,它只要一找到對(duì)應(yīng)名字的方法粉洼,就會(huì)返回,不會(huì)管后面可能還有一樣名字的方法叶摄。

4.Category為什么不能添加成員變量?

Category 可以給類增加方法和屬性,但是并不會(huì)自動(dòng)生成成員變量及set/get方法安拟。因?yàn)閏ategory_t結(jié)構(gòu)體中并不存在成員變量蛤吓。我們知道成員變量是存放在實(shí)例對(duì)象中的,并且編譯的那一刻就已經(jīng)決定好了糠赦。而分類是在運(yùn)行時(shí)才去加載的会傲。那么我們就無法再程序運(yùn)行時(shí)將分類的成員變量中添加到實(shí)例對(duì)象的結(jié)構(gòu)體中锅棕。因此分類中不可以添加成員變量。

在 Objective-C 提供的 runtime 函數(shù)中淌山,確實(shí)有一個(gè) class_addIvar() 函數(shù)用于給類添加成員變量裸燎,但是閱讀過蘋果的官方文檔的人應(yīng)該會(huì)看到:

This function may only be called after objc_allocateClassPair and before objc_registerClassPair. Adding an instance variable to an existing class is not supported.


大概的意思說,這個(gè)函數(shù)只能在“構(gòu)建一個(gè)類的過程中”調(diào)用泼疑。當(dāng)編譯類的時(shí)候德绿,編譯器生成了一個(gè)實(shí)例變量?jī)?nèi)存布局 ivar layout,來告訴運(yùn)行時(shí)去那里訪問類的實(shí)例變量們退渗,一旦完成類定義移稳,就不能再添加成員變量了。經(jīng)過編譯的類在程序啟動(dòng)后就被 runtime 加載会油,沒有機(jī)會(huì)調(diào)用 addIvar个粱。程序在運(yùn)行時(shí)動(dòng)態(tài)構(gòu)建的類需要在調(diào)用 objc_registerClassPair 之后才可以被使用,同樣沒有機(jī)會(huì)再添加成員變量翻翩。

不能為一個(gè)類動(dòng)態(tài)的添加成員變量都许,可以給類動(dòng)態(tài)增加方法和屬性。因?yàn)榉椒ê蛯傩圆⒉弧皩儆凇鳖悓?shí)例嫂冻,而成員變量“屬于”類實(shí)例胶征。我們所說的“類實(shí)例”概念,指的是一塊內(nèi)存區(qū)域絮吵,包含了isa指針和所有的成員變量弧烤。所以假如允許動(dòng)態(tài)修改類成員變量布局,已經(jīng)創(chuàng)建出的類實(shí)例就不符合類定義了蹬敲,變成了無效對(duì)象暇昂。但方法定義是在objc_class中管理的,不管如何增刪類方法伴嗡,都不影響類實(shí)例的內(nèi)存布局急波,已經(jīng)創(chuàng)建出的類實(shí)例仍然可正常使用。

5.Category中有l(wèi)oad方法嗎瘪校?load方法是什么時(shí)候調(diào)用的澄暮?load 方法能繼承嗎?

在類和 category 中都可以有?+load方法,load方法在程序啟動(dòng)裝載類信息的時(shí)候就會(huì)調(diào)用阱扬。load方法可以繼承泣懊。調(diào)用子類的load方法之前,會(huì)先調(diào)用父類的load方法.

6.在類的?+load方法調(diào)用的時(shí)候麻惶,我們可以調(diào)用 category 中聲明的方法么馍刮?

可以調(diào)用,因?yàn)楦郊?category 到類的工作會(huì)先于?+load方法的執(zhí)行窃蹋。

7.這么些個(gè)+load方法卡啰,調(diào)用順序是咋樣的呢静稻?

+load的執(zhí)行順序是先類,后 category匈辱,而 category 的+load?執(zhí)行順序是根據(jù)編譯順序決定的振湾。雖然對(duì)于?+load的執(zhí)行順序是這樣,但是對(duì)于「覆蓋」掉的方法亡脸,則會(huì)先找到最后一個(gè)編譯的 category 里的對(duì)應(yīng)方法押搪。

子類的+load方法會(huì)在它的所有父類的+load方法之后執(zhí)行,而分類的+load方法會(huì)在它的主類的+load方法之后執(zhí)行梗掰,但是不同的類之間的+load方法的調(diào)用順序是不確定的嵌言,在Compile Sources中,文件的引入的先后順序決定不同的類之間的+load方法的調(diào)用順序及穗。

注意:+load方法調(diào)用時(shí)摧茴,如果調(diào)用別的類的方法,且該方法依賴于那個(gè)類的load方法進(jìn)行初始化設(shè)置埂陆,那么必須確保那個(gè)類的+load方法已經(jīng)調(diào)用了苛白,比如在Other類中調(diào)用Child類里面的方法,則打印出的字符串就為null焚虱。


Compile Sources 引入文件列表

8.怎么調(diào)用到原來類中被 category 覆蓋掉的方法购裙?

對(duì)于這個(gè)問題,我們已經(jīng)知道 category 其實(shí)并不是完全替換掉原來類的同名方法鹃栽,只是 category 在方法列表的前面而已躏率,所以我們只要順著方法列表找到最后一個(gè)對(duì)應(yīng)名字的方法,就可以調(diào)用原來類的方法

9.load民鼓、initialize的區(qū)別薇芝,以及它們?cè)赾ategory重寫的時(shí)候的調(diào)用的次序。

區(qū)別在于調(diào)用方式和調(diào)用時(shí)刻?

參考https://sunjinshuai.github.io/2016/08/16/iOS%E4%B9%8B-load%E5%92%8C-initialize%E7%9A%84%E5%8C%BA%E5%88%AB/

調(diào)用方式:load是根據(jù)函數(shù)地址直接調(diào)用丰嘉,initialize是通過objc_msgSend調(diào)用?

調(diào)用時(shí)刻:load是runtime加載類夯到、分類的時(shí)候調(diào)用(只會(huì)調(diào)用1次),initialize是類第一次接收到消息的時(shí)候調(diào)用饮亏,每一個(gè)類只會(huì)initialize一次(父類的initialize方法可能會(huì)被調(diào)用多次)

調(diào)用順序:

先調(diào)用類的load方法耍贾,先編譯那個(gè)類,就先調(diào)用load路幸。在調(diào)用load之前會(huì)先調(diào)用父類的load方法荐开。分類中l(wèi)oad方法不會(huì)覆蓋本類的load方法,先編譯的分類優(yōu)先調(diào)用load方法简肴。

initialize先初始化父類誓焦,之后再初始化子類。如果子類沒有實(shí)現(xiàn)+initialize着帽,會(huì)調(diào)用父類的+initialize(所以父類的+initialize可能會(huì)被調(diào)用多次)杂伟,如果分類實(shí)現(xiàn)了+initialize,就覆蓋類本身的+initialize調(diào)用仍翰。

參考:http://blog.leichunfeng.com/blog/2015/05/02/objective-c-plus-load-vs-plus-initialize/

10.category是如何為一個(gè)類添加屬性的

利用關(guān)聯(lián)對(duì)象

#import

"MyClass.h"

@interface MyClass (Category1)

@property(nonatomic,copy)NSString*name;

@end

#import "MyClass+Category1.h"

#import <objc/runtime.h>

@implementation MyClass (Category1)

+ (void)load

{

? ? NSLog(@"%@",@"load in Category1");

}

- (void)setName:(NSString *)name

{

? ? objc_setAssociatedObject(self,

? ? ? ? ? ? ? ? ? ? ? ? ? ? "name",

? ? ? ? ? ? ? ? ? ? ? ? ? ? name,

? ? ? ? ? ? ? ? ? ? ? ? ? ? OBJC_ASSOCIATION_COPY);

}

- (NSString*)name

{

? ? NSString *nameObject = objc_getAssociatedObject(self, "name");

? ? return nameObject;

}

@end

11.Category(類別)赫粥、 Extension(擴(kuò)展)和繼承的區(qū)別?分別用來做什么?

區(qū)別:

1. 分類有名字予借,類擴(kuò)展沒有分類名字越平,是一種特殊的分類。

2. 分類只能擴(kuò)展方法(屬性僅僅是聲明灵迫,并沒真正實(shí)現(xiàn))秦叛,類擴(kuò)展可以擴(kuò)展屬性、成員變量和方法瀑粥。

3. 繼承可以增加挣跋,修改或者刪除方法,并且可以增加屬性狞换。

就category和extension的區(qū)別來看避咆,我們可以推導(dǎo)出一個(gè)明顯的事實(shí),extension可以添加實(shí)例變量修噪,而category是無法添加實(shí)例變量的(因?yàn)樵谶\(yùn)行期查库,對(duì)象的內(nèi)存布局已經(jīng)確定,如果添加實(shí)例變量就會(huì)破壞類的內(nèi)部布局黄琼,這對(duì)編譯型語言來說是災(zāi)難性的)樊销。

extension在編譯期決議,它就是類的一部分脏款,但是category則完全不一樣围苫,它是在運(yùn)行期決議的。extension在編譯期和頭文件里的@interface以及實(shí)現(xiàn)文件里的@implement一起形成一個(gè)完整的類弛矛,它够吩、extension伴隨類的產(chǎn)生而產(chǎn)生,亦隨之一起消亡丈氓。

extension一般用來隱藏類的私有信息周循,你必須有一個(gè)類的源碼才能為一個(gè)類添加extension,所以你無法為系統(tǒng)的類比如NSString添加extension万俗,除非創(chuàng)建子類再添加extension湾笛。而category不需要有類的源碼,我們可以給系統(tǒng)提供的類添加category闰歪。

extension可以添加實(shí)例變量嚎研,而category不可以。

extension和category都可以添加屬性,但是category的屬性不能生成成員變量和getter临扮、setter方法的實(shí)現(xiàn)论矾。

(二)Extension

1、 什么是extension

extension被開發(fā)者稱之為擴(kuò)展杆勇、延展贪壳、匿名分類。extension看起來很像一個(gè)匿名的category蚜退,但是extension和category幾乎完全是兩個(gè)東西闰靴。和category不同的是extension不但可以聲明方法,還可以聲明屬性钻注、成員變量蚂且。extension一般用于聲明私有方法,私有屬性幅恋,私有成員變量杏死。

2、 extension的存在形式

category是擁有.h文件和.m文件的東西佳遣。但是extension不然识埋。extension只存在于一個(gè).h文件中,或者extension只能寄生于一個(gè)類的.m文件中零渐。比如窒舟,viewController.m文件中通常寄生這么個(gè)東西,其實(shí)這就是一個(gè)extension:

@interface?ViewController?()


@end

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末诵盼,一起剝皮案震驚了整個(gè)濱河市惠豺,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌风宁,老刑警劉巖洁墙,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異戒财,居然都是意外死亡热监,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門饮寞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來孝扛,“玉大人,你說我怎么就攤上這事幽崩】嗍迹” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵慌申,是天一觀的道長陌选。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么咨油? 我笑而不...
    開封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任您炉,我火速辦了婚禮,結(jié)果婚禮上臼勉,老公的妹妹穿的比我還像新娘邻吭。我一直安慰自己,他們只是感情好宴霸,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著膏蚓,像睡著了一般瓢谢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上驮瞧,一...
    開封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天氓扛,我揣著相機(jī)與錄音,去河邊找鬼论笔。 笑死采郎,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的狂魔。 我是一名探鬼主播蒜埋,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼最楷!你這毒婦竟也來了整份?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤籽孙,失蹤者是張志新(化名)和其女友劉穎烈评,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體犯建,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡讲冠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了适瓦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片竿开。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖犹菇,靈堂內(nèi)的尸體忽然破棺而出德迹,到底是詐尸還是另有隱情,我是刑警寧澤揭芍,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布胳搞,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏肌毅。R本人自食惡果不足惜筷转,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一耙替、第九天 我趴在偏房一處隱蔽的房頂上張望桶至。 院中可真熱鬧腰根,春花似錦惧浴、人聲如沸嫁赏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽哺窄。三九已至般婆,卻和暖如春到腥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蔚袍。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來泰國打工乡范, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人啤咽。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓晋辆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親宇整。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瓶佳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

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