關于Category,Extension的一些理解

(一)Category

特點:

category只能給某個已有的類擴充方法斋泄,不能擴充成員變量杯瞻。

category中也可以添加屬性,只不過@property只會生成setter和getter的聲明是己,不會生成setter和getter的實現(xiàn)以及成員變量又兵。

如果category中的方法和類中原有方法同名,運行時會優(yōu)先調(diào)用category中的方法卒废。也就是沛厨,category中的方法會覆蓋掉類中原有的方法。所以開發(fā)中盡量保證不要讓分類中的方法和原有類中的方法名相同摔认。避免出現(xiàn)這種情況的解決方案是給分類的方法名統(tǒng)一添加前綴逆皮。比如category_。

如果多個category中存在同名的方法参袱,運行時到底調(diào)用哪個方法由編譯器決定电谣,最后一個參與編譯的方法會被調(diào)用。這個要看在xcode配置中抹蚀,他們的.m 是在前還是在后剿牺,放在上面的先編譯,那么后面編譯的category同名方法就會被調(diào)用环壤。

結構:

Category不允許為已有的類添加新的成員變量晒来,實際上允許添加屬性的,同樣可以使用@property郑现,但是不會生成_變量(帶下劃線的成員變量)湃崩,也不會生成添加屬性的getter和setter方法,所以接箫,盡管添加了屬性攒读,也無法使用點語法調(diào)用getter和setter方法。

我們看下category的結構:

typedef?struct?category_t?{

const?char?*name;??//類的名字

classref_t?cls;??//類

struct?method_list_t?*instanceMethods;??//category中所有給類添加的實例方法的列表

struct?method_list_t?*classMethods;??//category中所有添加的類方法的列表

struct?protocol_list_t?*protocols;??//category實現(xiàn)的所有協(xié)議的列表

struct?property_list_t?*instanceProperties;??//category中添加的所有屬性

}?category_t;

我們看到它是有instanceProperties這樣一個數(shù)組的辛友,那么為什么說無法添加屬性薄扁,其實是添加后不會自動生成get,set方法而已废累,所以在使用 點語法的時候邓梅,回報找不到方法的錯誤提示。

因此我們需要使用runtime動態(tài)的給category添加對應的get,set方法九默。

添加屬性的案例,比如給一個分類添加 blog這樣一個屬性:

@property (nonatomic, copy) NSString *blog;

- (NSString *)blog

{

????// 根據(jù)關聯(lián)的key震放,獲取關聯(lián)的值。

????return objc_getAssociatedObject(self, key);

}

/**

blog的setter方法

*/

- (void)setBlog:(NSString *)blog

{

????// 第一個參數(shù):給哪個對象添加關聯(lián)

????// 第二個參數(shù):關聯(lián)的key驼修,通過這個key獲取

????// 第三個參數(shù):關聯(lián)的value

????// 第四個參數(shù):關聯(lián)的策略

????objc_setAssociatedObject(self, key, blog, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

}

另外需要注意的有兩點:

1)殿遂、category的方法沒有“完全替換掉”原來類已經(jīng)有的方法,也就是說如果category和原來類都有methodA乙各,那么category附加完成之后墨礁,類的方法列表里會有兩個methodA。

2)耳峦、category的方法被放到了新方法列表的前面恩静,而原來類的方法被放到了新方法列表的后面,這也就是我們平常所說的category的方法會“覆蓋”掉原來類的同名方法,這是因為運行時在查找方法的時候是順著方法列表的順序查找的驶乾,它只要一找到對應名字的方法邑飒,就會罷休,殊不知后面可能還有一樣名字的方法级乐。

(二)Extension

extension被開發(fā)者稱之為擴展疙咸、延展、匿名分類风科。extension看起來很像一個匿名的category撒轮,但是extension和category幾乎完全是兩個東西。和category不同的是extension不但可以聲明方法贼穆,還可以聲明屬性题山、成員變量。extension一般用于聲明私有方法故痊,私有屬性顶瞳,私有成員變量。

比如很的.m 文件里面會在implementation 上面加個

@interface viewModel() //這就是extension崖蜜,可以添加屬性浊仆, 方法一般用于私有方法,私有屬性豫领,成員變量

@implementation ViewModel

(三)category和extension的區(qū)別

就category和extension的區(qū)別來看抡柿,我們可以推導出一個明顯的事實,extension可以添加實例變量等恐,而category是無法添加實例變量的(因為在運行期洲劣,對象的內(nèi)存布局已經(jīng)確定,如果添加實例變量就會破壞類的內(nèi)部布局课蔬,這對編譯型語言來說是災難性的)囱稽。

extension在編譯期決議,它就是類的一部分二跋,但是category則完全不一樣战惊,它是在運行期決議的。extension在編譯期和頭文件里的@interface以及實現(xiàn)文件里的@implement一起形成一個完整的類扎即,它吞获、extension伴隨類的產(chǎn)生而產(chǎn)生,亦隨之一起消亡谚鄙。

extension一般用來隱藏類的私有信息各拷,你必須有一個類的源碼才能為一個類添加extension,所以你無法為系統(tǒng)的類比如NSString添加extension闷营,除非創(chuàng)建子類再添加extension烤黍。而category不需要有類的源碼,我們可以給系統(tǒng)提供的類添加category。

extension可以添加實例變量速蕊,而category不可以栅炒。

extension和category都可以添加屬性裙顽,但是category的屬性不能生成成員變量和getter闹瞧、setter方法的實現(xiàn)这敬。

補充:

那么category 中關聯(lián)的屬性是存放在哪里呢筝闹,又如何銷毀:
從runtime的源碼中可以看到媳叨,這里其實所有的關聯(lián)對象都由AssociationsManager管理,AssociationsManager里面是由一個靜態(tài)AssociationsHashMap來存儲所有的關聯(lián)對象的关顷。這相當于把所有對象的關聯(lián)對象都存在一個全局map里面糊秆。而map的的key是這個對象的指針地址(任意兩個不同對象的指針地址一定是不同的),而這個map的value又是另外一個AssociationsHashMap议双,里面保存了關聯(lián)對象的kv對痘番。

銷毀:runtime的銷毀對象函數(shù)objc_destructInstance里面會判斷這個對象有沒有關聯(lián)對象,如果有平痰,會調(diào)用_object_remove_assocations做關聯(lián)對象的清理工作汞舱。

AssociationsManager定義如下:

class AssociationsManager {

? ? static OSSpinLock _lock;

? ? static AssociationsHashMap *_map;? ? ? ? ? ? ? // associative references:? object pointer -> PtrPtrHashMap.public:

? ? AssociationsManager()? { OSSpinLockLock(&_lock); }

? ? ~AssociationsManager()? { OSSpinLockUnlock(&_lock); }

? ? AssociationsHashMap &associations() {

? ? ? ? if (_map == NULL)

? ? ? ? ? ? _map = new AssociationsHashMap();

? ? ? ? return *_map;}}

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市宗雇,隨后出現(xiàn)的幾起案子昂芜,更是在濱河造成了極大的恐慌,老刑警劉巖赔蒲,帶你破解...
    沈念sama閱讀 222,464評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泌神,死亡現(xiàn)場離奇詭異,居然都是意外死亡舞虱,警方通過查閱死者的電腦和手機欢际,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來矾兜,“玉大人损趋,你說我怎么就攤上這事∫嗡拢” “怎么了浑槽?”我有些...
    開封第一講書人閱讀 169,078評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長配并。 經(jīng)常有香客問我括荡,道長,這世上最難降的妖魔是什么溉旋? 我笑而不...
    開封第一講書人閱讀 59,979評論 1 299
  • 正文 為了忘掉前任畸冲,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘邑闲。我一直安慰自己算行,他們只是感情好,可當我...
    茶點故事閱讀 69,001評論 6 398
  • 文/花漫 我一把揭開白布苫耸。 她就那樣靜靜地躺著州邢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪褪子。 梳的紋絲不亂的頭發(fā)上量淌,一...
    開封第一講書人閱讀 52,584評論 1 312
  • 那天,我揣著相機與錄音嫌褪,去河邊找鬼呀枢。 笑死,一個胖子當著我的面吹牛笼痛,可吹牛的內(nèi)容都是我干的裙秋。 我是一名探鬼主播,決...
    沈念sama閱讀 41,085評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼缨伊,長吁一口氣:“原來是場噩夢啊……” “哼摘刑!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起刻坊,我...
    開封第一講書人閱讀 40,023評論 0 277
  • 序言:老撾萬榮一對情侶失蹤枷恕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后紧唱,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體活尊,經(jīng)...
    沈念sama閱讀 46,555評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,626評論 3 342
  • 正文 我和宋清朗相戀三年漏益,在試婚紗的時候發(fā)現(xiàn)自己被綠了蛹锰。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,769評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡绰疤,死狀恐怖铜犬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情轻庆,我是刑警寧澤癣猾,帶...
    沈念sama閱讀 36,439評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站余爆,受9級特大地震影響纷宇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蛾方,卻給世界環(huán)境...
    茶點故事閱讀 42,115評論 3 335
  • 文/蒙蒙 一像捶、第九天 我趴在偏房一處隱蔽的房頂上張望上陕。 院中可真熱鬧,春花似錦拓春、人聲如沸释簿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽庶溶。三九已至,卻和暖如春懂鸵,著一層夾襖步出監(jiān)牢的瞬間偏螺,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評論 1 274
  • 我被黑心中介騙來泰國打工矾瑰, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留砖茸,地道東北人。 一個月前我還...
    沈念sama閱讀 49,191評論 3 378
  • 正文 我出身青樓殴穴,卻偏偏與公主長得像,于是被迫代替她去往敵國和親货葬。 傳聞我的和親對象是個殘疾皇子采幌,可洞房花燭夜當晚...
    茶點故事閱讀 45,781評論 2 361

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