Category中添加屬性和成員變量的區(qū)別

本文內(nèi)容由https://blog.csdn.net/intheair100/article/details/72718625修改的結(jié)果

類別的簡(jiǎn)介

在開發(fā)中有時(shí)會(huì)用到Category蝉衣,類別有三個(gè)作用:

(1)可以將類的時(shí)間分散到多個(gè)不同文件或多個(gè)不用框架中梗摇,方便代碼管理谢翎。也可以對(duì)框架提供類的擴(kuò)展(因?yàn)榭蚣茴悰]有源碼,不能修改)。

(2)創(chuàng)建對(duì)私有方法的前向引用:如果其他類的方法未實(shí)現(xiàn)匿情,在你訪問其他類的私有方法時(shí)編譯器報(bào)錯(cuò)扭倾,這時(shí)使用類別诅需,在類別中聲明這些方法漾唉,可以不必提供方法的實(shí)現(xiàn),編譯器就不會(huì)再產(chǎn)生警告了堰塌。

(3)向?qū)ο筇砑臃钦絽f(xié)議:創(chuàng)建一個(gè)NSObject的類別稱為“創(chuàng)建一個(gè)非正式協(xié)議”赵刑,因?yàn)榭梢宰鳛槿魏晤惖奈袑?duì)象使用。


有兩個(gè)方向的局限性:

(1)無法向類中添加新的實(shí)例變量场刑,類別沒有位置容納實(shí)例變量料睛。

(2)名稱沖突,即當(dāng)類別中的方法與原始類方法名稱沖突時(shí)摇邦,類別具有更高的優(yōu)先級(jí)。類別的方法將完全取代初始方法寵兒無法再使用初始方法屎勘。這個(gè)類似于方法的重載施籍,但是這里是直接覆蓋了原方法。

Category添加屬性:

@interface NSDate (CXExtension)

@property (nonatomic,assign,readonly) NSInteger day;
@property (nonatomic,assign,readonly) NSInteger month;
@property (nonatomic,assign,readonly) NSInteger year;
@property (nonatomic,assign,readonly) NSInteger firstWeek;
@property (nonatomic,assign,readonly) NSInteger totalDays;
@property (nonatomic,assign,readonly) NSDate *? lastMonth;
@property (nonatomic,assign,readonly) NSDate *? nextMonth;

@end

哎呦概漱,我擦嘞丑慎,什么鬼?怎么可以添加屬性了瓤摧?這個(gè)是為什么呢竿裂?

首先解釋一下屬性和成員變量的區(qū)別

屬性和成員變量的區(qū)別

@property(nonatomic,strong)UIButton*myButton;

我們聲明了一個(gè)屬性,我們現(xiàn)在用的編譯器已經(jīng)是LLVM了照弥,所以不再需要為屬性聲明實(shí)例變量了腻异。如果LLVM發(fā)現(xiàn)一個(gè)沒有匹配實(shí)例變量的屬性,它將為你生成以下劃線開頭的實(shí)例變量_mybutton,不需要自己手動(dòng)再去寫實(shí)例變量这揣。而且也不需要再.m文件中寫

@synthesize myButton

也會(huì)自動(dòng)生成setter悔常,getter方法影斑。@synthesize的作用就是讓編譯器為你生成setter和getter方法。那么.m文件中可以直接使用_myButton實(shí)例變量机打,也可以通過self.myButton矫户,兩者都是一樣的。當(dāng)然残邀,這里的self.myButton其實(shí)調(diào)用了myButton屬性的getter/setter方法皆辽。

假如我們?cè)贠bjective-C中

@interface TodayHomeViewController : UIViewController

{??? UIButton * myButton;?? }

.m文件中,self.myButtom 這樣的表達(dá)是錯(cuò)的芥挣,Xcode會(huì)提示你使用->,改成self->myButtom就可以了驱闷。因?yàn)镺C中的點(diǎn)表達(dá)式是表示調(diào)用方法,而上面的代碼中沒有myButton這個(gè)方法九秀。

Objective-C中的點(diǎn)語法說明:

如果點(diǎn)表達(dá)式出現(xiàn)在“=”左邊遗嗽,該屬性名稱的setter方法將被調(diào)用。如果點(diǎn)表達(dá)式出現(xiàn)在“=”右邊鼓蜒,該屬性名稱getter方法將會(huì)被調(diào)用痹换。所以在OC中點(diǎn)表達(dá)式其實(shí)就是調(diào)用對(duì)象setter和getter方法的一種快捷方式。

@synthesize 還有一個(gè)作用都弹,可以指定與屬性對(duì)應(yīng)的實(shí)力變量娇豫,例如

@synthesize myButton = xxxx;

那么self.myButton其實(shí)是操作實(shí)例變量xxxx,而不是_myButton了畅厢。


在實(shí)際開發(fā)中冯痢,我們一般在.m中這樣寫:

@synthesize?? myButton;

這樣寫了之后,那么編譯器會(huì)自動(dòng)生成myButton的實(shí)例變量框杜,以及相應(yīng)的getter和setter方法浦楣。注意:_myButton這個(gè)實(shí)例變量是不存在的,因?yàn)樽詣?dòng)生成的實(shí)例變量是myButton而不是_myButton咪辱,所以現(xiàn)在@synthesize的作用就相當(dāng)于枝頂實(shí)例變量振劳。

如果在.m中寫了

@synthesize myButton;

那么生成的實(shí)例變量就是myButton,如果沒有寫

@synthesize myButton;

那么生成的實(shí)例變量就是_myButton油狂。所以跟以前的用法還是有點(diǎn)細(xì)微的區(qū)別的历恐。

Category中屬性Property

類別中只能添加方法,不能添加實(shí)例變量专筷。我們經(jīng)橙踉簦看見類別中這樣寫:

@property(nonatomic, assign) CGFloat? x;

在這種情況下一般不會(huì)生成實(shí)例變量的,這里添加的屬性磷蛹,其實(shí)是添加的setter和getter方法吮旅。

- (void)setX:(CGFloat)x{
??? CGRect rect = self.frame;
??? rect.origin.x = x;
??? self.frame = rect;
}

- (CGFloat)x{
??? return self.frame.origin.x;
}

在Objective-C提供的runtime函數(shù)中,確實(shí)有一個(gè)class_addIvar()刪除可以給類別添加成員變量味咳,但是文檔中特別說明:

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)用鸟辅。一旦完成類定義氛什,就不能再添加成員變量了。經(jīng)過編譯的類在程序啟動(dòng)后runtime加載匪凉,沒有機(jī)會(huì)調(diào)用addIver枪眉。程序在運(yùn)行時(shí)動(dòng)態(tài)構(gòu)建的類需要在調(diào)用objc_allocateClassPair之后,ojbc_registerClassPair之前被使用再层,同樣沒有機(jī)會(huì)再添加成員變量贸铜。那么為什么可以在類別中添加方法和屬性呢?

因?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í)例仍然可以正常使用。

在類別中添加實(shí)例變量

那我們?nèi)绻砑訉?shí)例變量該怎么辦呢旧困?這個(gè)使用就該用runtime了醇份,不要忘記Objective-C是一門動(dòng)態(tài)的語言,常見的辦法是通過runtime.h中objc_getAssociateObject / objc_setAssociateObject來訪問和生成關(guān)聯(lián)對(duì)象吼具。這兩個(gè)方法可以讓一個(gè)對(duì)象和另一個(gè)對(duì)象關(guān)聯(lián)僚纷,就是說一個(gè)對(duì)象可以保持對(duì)另一個(gè)對(duì)象的引用,并獲得那個(gè)對(duì)象拗盒。

//NSObject+IndieBandName.h

@interfaceNSObject (IndieBandName)

@property(nonatomic, strong) NSString *indieBandName;

@end

上面是頭文件聲明怖竭,接下來就是見證奇跡的時(shí)刻,實(shí)現(xiàn).m文件:

// NSObject+IndieBandName.m

#import "NSObject+Extension.h"

#import <objc/runtime.h>

static const void *IndieBandNameKey = &IndieBandNameKey;

@implementation NSObject (IndieBandName)

@dynamic indieBandName;

- (NSString *)indieBandName {

return objc_getAssociatedObject(self, IndieBandNameKey);

}

- (void)setIndieBandName:(NSString *)indieBandName {

objc_setAssociatedObject(self, IndieBandNameKey, indieBandName, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

}

@end

通過runtime的兩種方法就可以為列別添加一個(gè)實(shí)例變量了锣咒。

本文是有底線的


感謝各位大牛的資料

http://www.cnblogs.com/crazypebble/p/3439261.html

https://blog.csdn.net/intheair100/article/details/72718625

http://quotation.github.io/objc/2015/05/21/objc-runtime-ivar-access.html

http://www.cnblogs.com/wupher/archive/2013/01/05/2845338.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市赞弥,隨后出現(xiàn)的幾起案子毅整,更是在濱河造成了極大的恐慌,老刑警劉巖绽左,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件悼嫉,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡拼窥,警方通過查閱死者的電腦和手機(jī)戏蔑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門蹋凝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人总棵,你說我怎么就攤上這事鳍寂。” “怎么了情龄?”我有些...
    開封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵迄汛,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我骤视,道長(zhǎng)鞍爱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任专酗,我火速辦了婚禮睹逃,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘祷肯。我一直安慰自己沉填,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開白布躬柬。 她就那樣靜靜地躺著拜轨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪允青。 梳的紋絲不亂的頭發(fā)上橄碾,一...
    開封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音颠锉,去河邊找鬼。 笑死拒垃,一個(gè)胖子當(dāng)著我的面吹牛悼瓮,可吹牛的內(nèi)容都是我干的艰猬。 我是一名探鬼主播冠桃,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼污茵!你這毒婦竟也來了泞当?” 一聲冷哼從身側(cè)響起玷室,我...
    開封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤穷缤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后章喉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體秸脱,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡摊唇,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了抹腿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片警绩。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡后室,死狀恐怖混狠,靈堂內(nèi)的尸體忽然破棺而出檀蹋,到底是詐尸還是另有隱情,我是刑警寧澤贸桶,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站水醋,受9級(jí)特大地震影響彪置,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜惶桐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望授舟。 院中可真熱鬧释树,春花似錦、人聲如沸署浩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽襟交。三九已至捣域,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間迹鹅,已是汗流浹背贞言。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工弟蚀, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留酗失,地道東北人规肴。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓鉴嗤,卻偏偏與公主長(zhǎng)得像序调,于是被迫代替她去往敵國(guó)和親发绢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

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