Category與Extension

Category

  • 概述:Category是OC2.0之后添加的語言特性研叫,Category又叫類別,分類等璧针,能夠在不改變原來類的內(nèi)容基礎(chǔ)上嚷炉,為類增加一些方法(當(dāng)然還有大家都知道的,雖然不能以正常方式為類添加屬性探橱,但是我們可以通過runtime來動態(tài)綁定添加申屹,后面會講到),除此之外Category還有以下功能
  1. 將類的實(shí)現(xiàn)分開寫在幾個分類里面隧膏,這樣做的好處是
  • 可以減少單個文件的體積
  • 可以把不用的功能組織在不同的Category里
  • 可以由多個開發(fā)者共同完成一個類
  • 可以按需加載想要的Category
  1. 聲明私有的方法
  2. 模擬多繼承
  • 使用
    既然我們說Category只能為類增加方法哗讥,而不能添加屬性,那么我們就去創(chuàng)建一個分類文件去驗(yàn)證以下胞枕,看看具體是個什么樣的情況杆煞。

我們創(chuàng)建了一個Student和他的分類Student+Category

@interface Student : NSObject
@property (nonatomic,copy) NSString *age;
@property (nonatomic,copy) NSString *name;
@end
//Student+Category.h
@interface Student (Category)
@property (nonatomic,copy) NSString *schoolName;
@end

我們運(yùn)行一下,可以發(fā)現(xiàn)他編譯成功了并且運(yùn)行成功了腐泻,


image
image

放開斷點(diǎn)發(fā)現(xiàn)崩潰了决乎,看錯誤日志我們知道了沒有setSchoolName方法。那么問題來了派桩,既然我們可以在分類中添加屬性瑞驱,但在調(diào)用的時(shí)候卻會奔潰,這是為什么窄坦,我們先來看看Category的源碼

Category
Category 是表示一個指向分類的結(jié)構(gòu)體的指針唤反,其定義如下:
typedef struct objc_category *Category;
struct objc_category {
  char *category_name                          OBJC2_UNAVAILABLE; // 分類名
  char *class_name                             OBJC2_UNAVAILABLE; // 分類所屬的類名
  struct objc_method_list *instance_methods    OBJC2_UNAVAILABLE; // 實(shí)例方法列表
  struct objc_method_list *class_methods       OBJC2_UNAVAILABLE; // 類方法列表
  struct objc_protocol_list *protocols         OBJC2_UNAVAILABLE; // 分類所實(shí)現(xiàn)的協(xié)議列表
}

我們看到了什么凳寺,我們有發(fā)現(xiàn)實(shí)例方法列表,類方法類表彤侍,協(xié)議列表肠缨,但是沒有屬性列表。我們知道在一個類中用 @property 聲明屬性盏阶,編譯器會自動幫我們生成 _成員變量名 和setter,getter方法晒奕,但是在分類的指針結(jié)構(gòu)體中,根本就要沒有屬性類表名斟,所以也就不能生成 _成員變量名 和setter,getter方法脑慧,因此我們的程序可以編譯和運(yùn)行都成功了,但是一旦有調(diào)用這個屬性就會奔潰砰盐。

解決方案

  • 由于OC是動態(tài)語言闷袒,方法真正的實(shí)現(xiàn)是通過runtime完成的,雖然系統(tǒng)不給我們生成setter/getter岩梳,但我們可以通過runtime手動添加setter/getter方法
#import "Student+Category.h"
#import <objc/runtime.h>
static const char *schoolNameKey = "schoolNameKey";
@implementation Student (Category)
- (void)setSchoolName:(NSString *)schoolName{
    objc_setAssociatedObject(self, &schoolNameKey, schoolName, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *)schoolName{
    return objc_getAssociatedObject(self, &schoolNameKey);
}
@end
  • 總結(jié)
  1. 分類是用于給原有類添加方法的,因?yàn)榉诸惖慕Y(jié)構(gòu)體指針中囊骤,沒有屬性列表,只有方法列表冀值。所以< 原則上講它只能添加方法, 不能添加屬性(成員變量),實(shí)際上可以通過其它方式添加屬性> ;
  2. 分類中的可以寫@property, 但不會生成setter/getter方法, 也不會生成實(shí)現(xiàn)以及私有的成員變量(編譯時(shí)會報(bào)警告);
  3. 可以在分類中訪問原有類中.h中的屬性;
  4. 如果分類中有和原有類同名的方法, 會優(yōu)先調(diào)用分類中的方法, 就是說會忽略原有類的方法也物。所以同名方法調(diào)用的優(yōu)先級為 分類 > 本類 > 父類。因此在開發(fā)中盡量不要覆蓋原有類;
  5. 如果多個分類中都有和原有類中同名的方法, 那么調(diào)用該方法的時(shí)候執(zhí)行誰由編譯器決定列疗;編譯器會執(zhí)行最后一個參與編譯的分類中的方法滑蚯。

Extension

  • Extension 是Category的一個特例,類擴(kuò)展與分類相比只少了分類的名稱以及.m文件抵栈,他常用的形式不是創(chuàng)建一個單獨(dú)的文件膘魄,而是在實(shí)現(xiàn)文件中添加私有的成員變量、屬性和方法竭讳。比如我們平時(shí)在創(chuàng)建一個類的時(shí)候我們會在.m文件中添加私有的成員變量、屬性和方法浙踢,當(dāng)然我們也可以在.h文件中添加绢慢,所以說Extension在我們平時(shí)的開發(fā)中是最常用的
@interface Student ()
{
    NSString *_core;
}
@property (nonatomic,copy) NSString *teachName;
- (void)study;
@end
  • 總結(jié)
  1. Extension的作用是為一個類添加額外的私有成員變量,屬性以及方法
  2. 一般的類擴(kuò)展寫到.m文件里

Category和Extension的區(qū)別

  1. Category原則中只能增加方法(能添加屬性的原因只是通過runtime解決沒有setter和getter方法)
  2. Extension不僅可以增加方法洛波,還可以增加屬性胰舆,只是屬性默認(rèn)的訪問權(quán)限是 private
  3. Extension中聲明的方法沒有在.m文件中實(shí)現(xiàn),編譯器會報(bào)警蹬挤,但是在Category中的方法沒有實(shí)現(xiàn)的話編譯器是不會有任何警告的缚窿。這是因?yàn)镋xtension是在編譯階段添加到類中,而Categor是在運(yùn)行時(shí)添加到類中的
  4. Extension不能像類別那樣擁有獨(dú)立的實(shí)現(xiàn)部分焰扳,他所聲明的方法只能在其對應(yīng)的類中實(shí)現(xiàn)
  5. Extension定義在.m文件的方法是私有的倦零,定義在.h文件的方法是公有的
  6. Extension一般用來隱藏類的私有消息误续,你必須有一個類的源碼才能添加一個類的Extension,所以對于系統(tǒng)一些類扫茅,如NSString蹋嵌,就無法添加類擴(kuò)展,如果只是簡單的創(chuàng)建Extension文件是能夠創(chuàng)建成功的,但是如果你在文件中添加屬性或者方法葫隙,在程序中一旦使用了該屬性或者方法程序就會崩潰栽烂,會報(bào)找不到相對應(yīng)的方法錯誤信息。

參考資料來源

  1. http://blog.csdn.net/haishu_zheng/article/details/12873151
  2. http://www.imlifengfeng.com/blog/?p=397
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末恋脚,一起剝皮案震驚了整個濱河市腺办,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌糟描,老刑警劉巖怀喉,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蚓挤,居然都是意外死亡磺送,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進(jìn)店門灿意,熙熙樓的掌柜王于貴愁眉苦臉地迎上來估灿,“玉大人,你說我怎么就攤上這事缤剧∠谠” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵荒辕,是天一觀的道長汗销。 經(jīng)常有香客問我,道長抵窒,這世上最難降的妖魔是什么弛针? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮李皇,結(jié)果婚禮上削茁,老公的妹妹穿的比我還像新娘。我一直安慰自己掉房,他們只是感情好茧跋,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著卓囚,像睡著了一般瘾杭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上哪亿,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天粥烁,我揣著相機(jī)與錄音贤笆,去河邊找鬼。 笑死页徐,一個胖子當(dāng)著我的面吹牛苏潜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播变勇,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼恤左,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了搀绣?” 一聲冷哼從身側(cè)響起飞袋,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎链患,沒想到半個月后巧鸭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡麻捻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年纲仍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贸毕。...
    茶點(diǎn)故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡郑叠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出明棍,到底是詐尸還是另有隱情乡革,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布摊腋,位于F島的核電站沸版,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏兴蒸。R本人自食惡果不足惜视粮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望橙凳。 院中可真熱鬧蕾殴,春花似錦、人聲如沸痕惋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽值戳。三九已至,卻和暖如春炉爆,著一層夾襖步出監(jiān)牢的瞬間堕虹,已是汗流浹背卧晓。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留赴捞,地道東北人逼裆。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像赦政,于是被迫代替她去往敵國和親胜宇。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評論 2 355

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