Category & Extension &關聯(lián)對象

Category

1、什么是Category?
category是Objective-C 2.0之后添加的語言特性,別人口中的分類晋渺、類別其實都是指的category。category的主要作用是為已經(jīng)存在的類添加方法脓斩。除此之外木西,apple還推薦了category的另外兩個使用場景。

可以把類的實現(xiàn)分開在幾個不同的文件里面随静。這樣做有幾個顯而易見的好處八千。

  • 可以減少單個文件的體積
  • 可以把不同的功能組織到不同的category里
  • 可以由多個開發(fā)者共同完成一個類
  • 可以按需加載想要的category
  • 聲明私有方法
    apple 的SDK中就大面積的使用了category這一特性。比如UIKit中的UIView燎猛。apple把不同的功能API進行了分類恋捆,這些分類包括UIViewGeometry、UIViewHierarchy重绷、UIViewRendering等沸停。

不過除了apple推薦的使用場景,廣大開發(fā)者腦洞大開昭卓,還衍生出了category的其他幾個使用場景:

  • 模擬多繼承(另外可以模擬多繼承的還有protocol)
  • 把framework的私有方法公開

2愤钾、category特點

  • category只能給某個已有的類擴充方法,不能擴充成員變量候醒。
  • category中也可以添加屬性能颁,只不過@property只會生成setter和getter的聲明,不會生成setter和getter的實現(xiàn)以及成員變量倒淫。
  • 如果category中的方法和類中原有方法同名伙菊,運行時會優(yōu)先調用category中的方法。也就是敌土,category中的方法會覆蓋掉類中原有的方法镜硕。所以開發(fā)中盡量保證不要讓分類中的方法和原有類中的方法名相同。避免出現(xiàn)這種情況的解決方案是給分類的方法名統(tǒng)一添加前綴纯赎。比如category_谦疾。
  • 如果多個category中存在同名的方法,運行時到底調用哪個方法由編譯器決定犬金,最后一個參與編譯的方法會被調用念恍。

3、調用優(yōu)先級
分類(category) > 本類 > 父類晚顷。即峰伙,優(yōu)先調用cateory中的方法,然后調用本類方法该默,最后調用父類方法瞳氓。
注意:category是在運行時加載的,不是在編譯時栓袖。

4匣摘、為什么category不能添加成員變量店诗?
Objective-C類是由Class類型來表示的,它實際上是一個指向objc_class結構體的指針音榜。它的定義如下:
typedef struct objc_class *Class;
objc_class結構體的定義如下:

struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
    Class super_class                       OBJC2_UNAVAILABLE;  // 父類
    const char *name                        OBJC2_UNAVAILABLE;  // 類名
    long version                            OBJC2_UNAVAILABLE;  // 類的版本信息庞瘸,默認為0
    long info                               OBJC2_UNAVAILABLE;  // 類信息,供運行期使用的一些位標識
    long instance_size                      OBJC2_UNAVAILABLE;  // 該類的實例變量大小
    struct objc_ivar_list *ivars            OBJC2_UNAVAILABLE;  // 該類的成員變量鏈表
    struct objc_method_list **methodLists   OBJC2_UNAVAILABLE;  // 方法定義的鏈表
    struct objc_cache *cache                OBJC2_UNAVAILABLE;  // 方法緩存
    struct objc_protocol_list *protocols    OBJC2_UNAVAILABLE;  // 協(xié)議鏈表
#endif
} OBJC2_UNAVAILABLE;

在上面的objc_class結構體中赠叼,ivars是objc_ivar_list(成員變量列表)指針擦囊;methodLists是指向objc_method_list指針的指針。在Runtime中嘴办,objc_class結構體大小是固定的瞬场,不可能往這個結構體中添加數(shù)據(jù),只能修改涧郊。所以ivars指向的是一個固定區(qū)域贯被,只能修改成員變量值,不能增加成員變量個數(shù)妆艘。methodList是一個二維數(shù)組刃榨,所以可以修改*methodLists的值來增加成員方法,雖沒辦法擴展methodLists指向的內存區(qū)域双仍,卻可以改變這個內存區(qū)域的值(存儲的是指針)枢希。因此,可以動態(tài)添加方法朱沃,不能添加成員變量苞轿。

5、category中能添加屬性嗎逗物?
Category不能添加成員變量(instance variables)搬卒,那到底能不能添加屬性(property)呢?

這個我們要從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;

從Category的定義也可以看出Category的可為(可以添加實例方法翎卓,類方法契邀,甚至可以實現(xiàn)協(xié)議,添加屬性)和不可為(無法添加實例變量)失暴。

但是為什么網(wǎng)上很多人都說Category不能添加屬性呢坯门?
實際上,Category實際上允許添加屬性的逗扒,同樣可以使用@property古戴,但是不會生成_變量(帶下劃線的成員變量),也不會生成添加屬性的getter和setter方法的實現(xiàn)矩肩,所以现恼,盡管添加了屬性,也無法使用點語法調用getter和setter方法(實際上,點語法是可以寫的叉袍,只不過在運行時調用到這個方法時候會報方法找不到的錯誤始锚,如下圖)。但實際上可以使用runtime去實現(xiàn)Category為已有的類添加新的屬性并生成getter和setter方法喳逛。

注意的有兩點:
1)疼蛾、category的方法沒有“完全替換掉”原來類已經(jīng)有的方法,也就是說如果category和原來類都有methodA艺配,那么category附加完成之后,類的方法列表里會有兩個methodA衍慎。
2)转唉、category的方法被放到了新方法列表的前面,而原來類的方法被放到了新方法列表的后面稳捆,這也就是我們平常所說的category的方法會“覆蓋”掉原來類的同名方法赠法,這是因為運行時在查找方法的時候是順著方法列表的順序查找的,它只要一找到對應名字的方法乔夯,就會罷休砖织,殊不知后面可能還有一樣名字的方法。

Extension

1末荐、 什么是extension
extension被開發(fā)者稱之為擴展侧纯、延展、匿名分類甲脏。extension看起來很像一個匿名的category眶熬,但是extension和category幾乎完全是兩個東西。和category不同的是extension不但可以聲明方法块请,還可以聲明屬性娜氏、成員變量。extension一般用于聲明私有方法墩新,私有屬性贸弥,私有成員變量。

2海渊、 extension的存在形式
category是擁有.h文件和.m文件的東西绵疲。但是extension不然。extension只存在于一個.h文件中臣疑,或者extension只能寄生于一個類的.m文件中最岗。比如,viewController.m文件中通常寄生這么個東西朝捆,其實這就是一個extension:

@interface ViewController ()
@end
當然我們也可以創(chuàng)建一個單獨的extension文件

注意:extension常用的形式并不是以一個單獨的.h文件存在般渡,而是寄生在類的.m文件中。

三)category和extension的區(qū)別
就category和extension的區(qū)別來看,我們可以推導出一個明顯的事實驯用,extension可以添加實例變量脸秽,而category是無法添加實例變量的(因為在運行期,對象的內存布局已經(jīng)確定蝴乔,如果添加實例變量就會破壞類的內部布局记餐,這對編譯型語言來說是災難性的)。

  • extension在編譯期決議薇正,它就是類的一部分片酝,但是category則完全不一樣,它是在運行期決議的挖腰。extension在編譯期和頭文件里的@interface以及實現(xiàn)文件里的@implement一起形成一個完整的類雕沿,它、extension伴隨類的產生而產生猴仑,亦隨之一起消亡审轮。
  • extension一般用來隱藏類的私有信息,你必須有一個類的源碼才能為一個類添加extension辽俗,所以你無法為系統(tǒng)的類比如NSString添加extension疾渣,除非創(chuàng)建子類再添加extension。而category不需要有類的源碼崖飘,我們可以給系統(tǒng)提供的類添加category榴捡。
  • extension可以添加實例變量,而category不可以朱浴。
  • extension和category都可以添加屬性薄疚,但是category的屬性不能生成成員變量和getter、setter方法的實現(xiàn)赊琳。

關聯(lián)對象

關聯(lián)對象是指某個OC對象通過一個唯一的key連接到一個類的實例上街夭。
舉個例子:xiaoming是Person類的一個實例,他的dog(一個OC對象)通過一根繩子(key)被他牽著散步躏筏,這可以說xiaoming和dog是關聯(lián)起來的板丽,當然xiaoming可以牽著多個dog。

設置關聯(lián)對象
void objc_setAssociatedObject(id object,const void*key, id value, objc_AssociationPolicy policy)

獲取關聯(lián)對象
void objc_getAssociatedObject(id object, const void *key)
    
移除關聯(lián)對象
void objc_removeAssociatedObjects(id object)

參數(shù)
id object 被關聯(lián)的對象(如xiaoming)
const void*key 關聯(lián)的key
 id value 關聯(lián)對象(如dog)
objc_AssociationPolicy policy 內存管理策略

當對象被釋放時趁尼,會根據(jù)這個策略來決定是否釋放關聯(lián)的對象埃碱,當策略是RETAIN/COPY時,會釋放(release)關聯(lián)的對象酥泞,當是ASSIGN砚殿,將不會釋放。
值得注意的是芝囤,我們不需要主動調用removeAssociated來接觸關聯(lián)的對象似炎,如果需要解除指定的對象辛萍,可以使用setAssociatedObject置nil來實現(xiàn)。

應用實例(Category添加屬性并生成getter和setter方法)
如何給NSArray添加一個屬性(不能使用繼承)羡藐?
我們現(xiàn)在為NSArray增加一個blog屬性:

NSArray+MyCategory.h文件:

#import <Foundation/Foundation.h>
@interface NSArray (MyCategory)
// 不會生成添加屬性的getter和setter方法贩毕,必須手動生成
@property(nonatomic,copy) NSString *blog;
@end

NSArray+MyCategory.m

#import "NSArray+MyCategory.h"
#import <objc/runtime.h>

@implementation NSArray (MyCategory)
// 定義關聯(lián)key
static const char *key = "blog";

/**
 blog的getter和setter方法
 */
- (NSString *)blog{
    // 根據(jù)關聯(lián)的key,獲取關聯(lián)的值
    return objc_getAssociatedObject(self, key);
}
- (void)setBlog:(NSString *)blog{
   
    objc_setAssociatedObject(self, key, blog, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end

調用

 NSArray *myarray = [[NSArray alloc] init];
 myarray.blog = @"123";
 NSLog(@"%@",myarray.blog);
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末仆嗦,一起剝皮案震驚了整個濱河市辉阶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌瘩扼,老刑警劉巖谆甜,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異集绰,居然都是意外死亡规辱,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進店門倒慧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人包券,你說我怎么就攤上這事纫谅。” “怎么了溅固?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵付秕,是天一觀的道長。 經(jīng)常有香客問我侍郭,道長询吴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任亮元,我火速辦了婚禮猛计,結果婚禮上,老公的妹妹穿的比我還像新娘爆捞。我一直安慰自己奉瘤,他們只是感情好,可當我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布煮甥。 她就那樣靜靜地躺著盗温,像睡著了一般。 火紅的嫁衣襯著肌膚如雪成肘。 梳的紋絲不亂的頭發(fā)上卖局,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天,我揣著相機與錄音双霍,去河邊找鬼砚偶。 笑死批销,一個胖子當著我的面吹牛,可吹牛的內容都是我干的蟹演。 我是一名探鬼主播风钻,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼酒请!你這毒婦竟也來了骡技?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤羞反,失蹤者是張志新(化名)和其女友劉穎布朦,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體昼窗,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡是趴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了澄惊。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唆途。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖掸驱,靈堂內的尸體忽然破棺而出柏卤,到底是詐尸還是另有隱情吟税,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站蒲每,受9級特大地震影響垒拢,放射性物質發(fā)生泄漏擂送。R本人自食惡果不足惜翘悉,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望待秃。 院中可真熱鬧拜秧,春花似錦、人聲如沸章郁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽驱犹。三九已至嘲恍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間雄驹,已是汗流浹背佃牛。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留医舆,地道東北人俘侠。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓象缀,卻偏偏與公主長得像,于是被迫代替她去往敵國和親爷速。 傳聞我的和親對象是個殘疾皇子央星,可洞房花燭夜當晚...
    茶點故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內容

  • (一)Category category是Objective-C 2.0之后添加的語言特性,別人口中的分類惫东、類別其...
    小李龍彪閱讀 2,959評論 0 10
  • 自己做筆錄 用來后來回顧莉给。。(一) Category1廉沮、什么是categorycategory是objective...
    41c48b8df394閱讀 3,515評論 1 8
  • 一 類別的簡介 在開發(fā)中有時會用到Category颓遏,類別有三個作用: (1)可以將類的實現(xiàn)分散到多個不同文件或多個...
    々莫等閑々閱讀 443評論 0 0
  • 面試題參考1 : 面試題[http://www.cocoachina.com/ios/20150803/12872...
    江河_ios閱讀 1,737評論 0 4
  • 今天是四個實習生在報社實習的最后一天滞时。 他們是當?shù)匾凰究茖W校文學院的大四學生叁幢。想必平日在學校里要么表現(xiàn)很優(yōu)秀,要...
    ld熊壯壯閱讀 248評論 0 1